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 14817be..f63f0a3 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 @@ -779,6 +779,12 @@ public static final String DEFAULT_AHS_ADDRESS = "0.0.0.0:" + DEFAULT_AHS_PORT; + public static final String AHS_WEB_ADDRESS = AHS_HISTORY_PREFIX + + "webapp.address"; + public static final int DEFAULT_AHS_WEB_PORT = 19887; + public static final String DEFAULT_AHS_WEB_ADDRESS = "0.0.0.0:" + + DEFAULT_AHS_WEB_PORT; + /** The number of threads to handle client API requests.*/ public static final String AHS_CLIENT_THREAD_COUNT = AHS_HISTORY_PREFIX + "client.thread-count"; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/YarnWebParams.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/YarnWebParams.java index 1f59b87..91d2a20 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/YarnWebParams.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/YarnWebParams.java @@ -24,6 +24,7 @@ public interface YarnWebParams { String NM_NODENAME = "nm.id"; String APPLICATION_ID = "app.id"; + String APPLICATION_ATTEMPT_ID = "appattempt.id"; String CONTAINER_ID = "container.id"; String CONTAINER_LOG_TYPE= "log.type"; String ENTITY_STRING = "entity.string"; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/AHSWebServer.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/AHSWebServer.java index fba5ef8..fdd90fd 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/AHSWebServer.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/AHSWebServer.java @@ -18,12 +18,46 @@ package org.apache.hadoop.yarn.server.applicationhistoryservice; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.service.AbstractService; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; +import org.apache.hadoop.yarn.server.applicationhistoryservice.webapp.AHSWebApp; +import org.apache.hadoop.yarn.webapp.WebApps; public class AHSWebServer extends AbstractService { + private static final Log LOG = LogFactory.getLog(AHSWebServer.class); + private AHSWebApp webApp; + private final ApplicationHistoryClientService ahsClientService; - public AHSWebServer() { + public AHSWebServer(ApplicationHistoryReader appHistoryReader, + ApplicationHistoryClientService ahsClientService) { super(AHSWebServer.class.getName()); + this.ahsClientService = ahsClientService; + webApp = new AHSWebApp(appHistoryReader); } -} + @Override + protected void serviceStart() throws Exception { + String bindAddress = getConfig().get(YarnConfiguration.AHS_WEB_ADDRESS, + YarnConfiguration.DEFAULT_AHS_WEB_ADDRESS); + LOG.info("Instantiating AHSWebApp at " + bindAddress); + try { + WebApps + .$for("applicationhistory", ApplicationHistoryClientService.class, + ahsClientService, "ws").with(getConfig()).at(bindAddress) + .start(webApp); + } catch (Exception e) { + String msg = "AHSWebapps failed to start."; + LOG.error(msg, e); + throw new YarnRuntimeException(msg, e); + } + super.serviceStart(); + } + + @Override + protected void serviceStop() throws Exception { + super.serviceStop(); + } +} \ No newline at end of file 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 3ed3546..5ae5ab6 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 @@ -25,7 +25,9 @@ import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.metrics2.source.JvmMetrics; import org.apache.hadoop.service.CompositeService; +import org.apache.hadoop.service.Service; import org.apache.hadoop.util.ExitUtil; +import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.ShutdownHookManager; import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.yarn.YarnUncaughtExceptionHandler; @@ -36,7 +38,8 @@ * Application specific history to start with. */ public class ApplicationHistoryServer extends CompositeService { - + public static final long appHistoryServerTimeStamp = System + .currentTimeMillis(); public static final int SHUTDOWN_HOOK_PRIORITY = 30; private static final Log LOG = LogFactory.getLog(ApplicationHistoryServer.class); @@ -51,14 +54,21 @@ public ApplicationHistoryServer() { @Override protected void serviceInit(Configuration conf) throws Exception { - super.serviceInit(conf); historyService = new ApplicationHistory(); historyContext = (ApplicationHistoryContext) historyService; ahsClientService = new ApplicationHistoryClientService(historyContext); addService(ahsClientService); addService(historyService); - AHSWebServer webServer = new AHSWebServer(); + ApplicationHistoryStore historyStore = ReflectionUtils.newInstance(conf + .getClass(YarnConfiguration.AHS_STORAGE, + FileSystemApplicationHistoryStore.class, + ApplicationHistoryStore.class), conf); + if (historyStore instanceof Service) { + ((Service) historyStore).init(conf); + } + AHSWebServer webServer = new AHSWebServer(historyStore, ahsClientService); addService(webServer); + super.serviceInit(conf); } @Override diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAboutPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAboutPage.java new file mode 100644 index 0000000..86be96f --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAboutPage.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; + +import org.apache.hadoop.yarn.server.applicationhistoryservice.webapp.dao.AHSInfo; +import org.apache.hadoop.yarn.util.Times; +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.view.InfoBlock; + +public class AHSAboutPage extends AHSView { + + @Override + protected void preHead(Page.HTML<_> html) { + commonPreHead(html); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:0}"); + } + + @Override + protected Class content() { + AHSInfo info = new AHSInfo(); + info("Application History Server")._("BuildVersion", + info.getHadoopBuildVersion() + " on " + info.getHadoopVersionBuiltOn()) + ._("Application History Server started on", + Times.format(info.getStartedOn())); + return InfoBlock.class; + } +} \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptBlock.java new file mode 100644 index 0000000..ee58cb6 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptBlock.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationAttemptHistoryData; +import org.apache.hadoop.yarn.util.ConverterUtils; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; +import org.apache.hadoop.yarn.webapp.view.InfoBlock; + +import com.google.inject.Inject; + +public class AHSAppAttemptBlock extends HtmlBlock { + + private static final Log LOG = LogFactory.getLog(AHSAppAttemptBlock.class); + private final ApplicationHistoryReader appHistoryReader; + + @Inject + public AHSAppAttemptBlock(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + protected void render(Block html) { + String attemptid = $(YarnWebParams.APPLICATION_ATTEMPT_ID); + if (attemptid.isEmpty()) { + html. + p()._("Sorry, can't do anything without a App Attempt Id.")._(); + return; + } + ApplicationAttemptId appAttemptId = ConverterUtils.toApplicationAttemptId(attemptid); + ApplicationAttemptHistoryData applicationAttempt; + try { + applicationAttempt = appHistoryReader.getApplicationAttempt(appAttemptId); + } catch (IOException e) { + String message = "Failed to read application attempts."; + LOG.error(message, e); + html.p()._(message)._(); + return; + } + info("Application Attempt Overview"). + _("Attempt ID:", applicationAttempt.getApplicationAttemptId()). + _("Host:", applicationAttempt.getHost()). + _("RPC Port:", applicationAttempt.getRPCPort()). + _("Tracking URL:", "" + applicationAttempt.getTrackingURL() + ""). + _("Diagnostics Info:", applicationAttempt.getDiagnosticsInfo()). + _("Final Application Status:", applicationAttempt.getFinalApplicationStatus()). + _("Master Container Id:", root_url("container", applicationAttempt.getMasterContainerId().toString()), + String.valueOf(applicationAttempt.getMasterContainerId())); + html._(InfoBlock.class).div(_INFO_WRAP); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptContainersBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptContainersBlock.java new file mode 100644 index 0000000..4c6e3ed --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptContainersBlock.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import java.io.IOException; +import java.util.Collection; + +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ContainerHistoryData; +import org.apache.hadoop.yarn.util.ConverterUtils; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +import com.google.inject.Inject; + +public class AHSAppAttemptContainersBlock extends AHSAppContainersBlock { + + @Inject + public AHSAppAttemptContainersBlock(ApplicationHistoryReader appHistoryReader) { + super(appHistoryReader); + } + + @Override + protected void render(Block html) { + String id = $(YarnWebParams.APPLICATION_ATTEMPT_ID); + if (id.isEmpty()) { + html.p()._("Sorry, can't do anything without a AppAttempt Id.")._(); + return; + } + Collection containers; + try { + ApplicationAttemptId applicationAttemptId = ConverterUtils + .toApplicationAttemptId(id); + containers = appHistoryReader.getContainers(applicationAttemptId) + .values(); + } catch (IOException e) { + html.p()._("Sorry, Failed to get containers for appattempt id:" + id) + ._(); + return; + } + renderContainersTable(html, containers); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptContainersPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptContainersPage.java new file mode 100644 index 0000000..0d44f42 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptContainersPage.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.join; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSAppAttemptContainersPage extends AHSAppContainersPage { + + @Override + protected void initTitle() { + String appAttemptId = $(YarnWebParams.APPLICATION_ATTEMPT_ID); + set(TITLE, appAttemptId.isEmpty() ? "Bad request: missing application attempt ID" : join( + "YARN Application Attempt ", $(YarnWebParams.APPLICATION_ATTEMPT_ID))); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:2}"); + } + + @Override + protected Class content() { + return AHSAppAttemptContainersBlock.class; + } +} \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptPage.java new file mode 100644 index 0000000..e26c745 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptPage.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.join; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSAppAttemptPage extends AHSView { + + @Override + protected void preHead(Page.HTML<_> html) { + String appId = $(YarnWebParams.APPLICATION_ATTEMPT_ID); + set(TITLE, appId.isEmpty() ? "Bad request: missing application attempt ID" : join( + "YARN Application Attempt ", $(YarnWebParams.APPLICATION_ATTEMPT_ID))); + commonPreHead(html); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:2}"); + } + + @Override + protected Class content() { + return AHSAppAttemptBlock.class; + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptsBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptsBlock.java new file mode 100644 index 0000000..709af68 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptsBlock.java @@ -0,0 +1,107 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._EVEN; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._ODD; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH; + +import java.io.IOException; +import java.util.Collection; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationAttemptHistoryData; +import org.apache.hadoop.yarn.util.Apps; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.DIV; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; + +import com.google.inject.Inject; + +public class AHSAppAttemptsBlock extends HtmlBlock { + + private static final Log LOG = LogFactory.getLog(AHSAppAttemptsBlock.class); + private final ApplicationHistoryReader appHistoryReader; + + @Inject + public AHSAppAttemptsBlock(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + protected void render(Block html) { + String appid = $(YarnWebParams.APPLICATION_ID); + if (appid.isEmpty()) { + html. + p()._("Sorry, can't do anything without a App Id.")._(); + return; + } + ApplicationId applicationId = Apps.toAppID(appid); + + DIV div = html.div(_INFO_WRAP); + Collection applicationAttempts; + try { + applicationAttempts = appHistoryReader.getApplicationAttempts( + applicationId).values(); + } catch (IOException e) { + String message = "Failed to read application attempts."; + LOG.error(message, e); + html.p()._(message)._(); + return; + } + String amString = + applicationAttempts.size() >1 ? "ApplicationMasters" : "ApplicationMaster"; + + TABLE> table = div.table("#attempts"); + table. + tr(). + th(amString)._(). + tr(). + th(_TH, "Attempt Number"). + th(_TH, "Host"). + th(_TH, "RPC Port"). + th(_TH, "Tracking URL"). + th(_TH, "Diagnostics Info"). + th(_TH, "Final Application Status"). + th(_TH, "Master Container Id"). + _(); + + boolean odd = false; + for (ApplicationAttemptHistoryData attemptData : applicationAttempts) { + ApplicationAttemptId appAttemptId = attemptData.getApplicationAttemptId(); + table.tr((odd = !odd) ? _ODD : _EVEN). + td().a(url("appattempt", appAttemptId.toString()), String.valueOf(appAttemptId.getAttemptId()))._(). + td(attemptData.getHost()). + td(String.valueOf(attemptData.getRPCPort())). + td(attemptData.getTrackingURL()). + td(attemptData.getDiagnosticsInfo()). + td(String.valueOf(attemptData.getFinalApplicationStatus())). + td().a(url("container", attemptData.getMasterContainerId().toString()), + String.valueOf(attemptData.getMasterContainerId()))._()._(); + } + table._(); + div._(); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptsPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptsPage.java new file mode 100644 index 0000000..b6b768e --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppAttemptsPage.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.join; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSAppAttemptsPage extends AHSView { + + @Override + protected void preHead(Page.HTML<_> html) { + String appId = $(YarnWebParams.APPLICATION_ID); + set(TITLE, appId.isEmpty() ? "Bad request: missing application ID" : join( + "YARN Application ", $(YarnWebParams.APPLICATION_ID))); + commonPreHead(html); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:1}"); + } + + @Override + protected Class content() { + return AHSAppAttemptsBlock.class; + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainerBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainerBlock.java new file mode 100644 index 0000000..e22d9ba --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainerBlock.java @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; + +import java.io.IOException; +import java.util.Date; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.util.StringUtils; +import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ContainerHistoryData; +import org.apache.hadoop.yarn.util.ConverterUtils; +import org.apache.hadoop.yarn.util.Times; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; +import org.apache.hadoop.yarn.webapp.view.InfoBlock; + +import com.google.inject.Inject; + +public class AHSAppContainerBlock extends HtmlBlock { + + private static final Log LOG = LogFactory.getLog(AHSAppContainerBlock.class); + private final ApplicationHistoryReader appHistoryReader; + + @Inject + public AHSAppContainerBlock(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + protected void render(Block html) { + String containerid = $(YarnWebParams.CONTAINER_ID); + if (containerid.isEmpty()) { + html. + p()._("Sorry, can't do anything without a Container Id.")._(); + return; + } + ContainerId containerId = ConverterUtils.toContainerId(containerid); + html.div(_INFO_WRAP); + ContainerHistoryData containerHistoryData; + try { + containerHistoryData = appHistoryReader.getContainer(containerId); + } catch (IOException e) { + String message = "Failed to read Container Data."; + LOG.error(message, e); + html.p()._(message)._(); + return; + } + info("Container Overview"). + _("Container Id:", containerHistoryData.getContainerId()). + _("Assigned Node:", containerHistoryData.getAssignedNode()). + _("Priority:", containerHistoryData.getPriority()). + _("Start Time:", containerHistoryData.getStartTime()). + _("Finish Time:", new Date(containerHistoryData.getFinishTime())). + _("Diagnostics Info:", containerHistoryData.getDiagnosticsInfo()). + _("Final Container Status:", containerHistoryData.getFinalContainerStatus()). + _("Logs:", containerHistoryData.getLogURL()). + _("Elapsed:", StringUtils.formatTime( + Times.elapsed(containerHistoryData.getStartTime(), + containerHistoryData.getFinishTime(), false))); + html._(InfoBlock.class).div(_INFO_WRAP); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainerPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainerPage.java new file mode 100644 index 0000000..713efa7 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainerPage.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.join; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSAppContainerPage extends AHSView { + + @Override + protected void preHead(Page.HTML<_> html) { + String containerid = $(YarnWebParams.CONTAINER_ID); + set(TITLE, containerid.isEmpty() ? "Bad request: missing Container ID" : join( + "YARN Application Container ", $(YarnWebParams.CONTAINER_ID))); + commonPreHead(html); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:1}"); + } + + @Override + protected Class content() { + return AHSAppContainerBlock.class; + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainersBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainersBlock.java new file mode 100644 index 0000000..ba575aa --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainersBlock.java @@ -0,0 +1,130 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Set; + +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ContainerHistoryData; +import org.apache.hadoop.yarn.util.Apps; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TBODY; +import org.apache.hadoop.yarn.webapp.hamlet.HamletSpec.InputType; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; + +import com.google.inject.Inject; + +public class AHSAppContainersBlock extends HtmlBlock { + + private final SimpleDateFormat dateFormat = new SimpleDateFormat( + "yyyy.MM.dd HH:mm:ss z"); + protected final ApplicationHistoryReader appHistoryReader; + + @Inject + public AHSAppContainersBlock(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + protected void render(Block html) { + String id = $(YarnWebParams.APPLICATION_ID); + if (id.isEmpty()) { + html.p()._("Sorry, can't do anything without a App Id.")._(); + return; + } + Collection containers; + try { + ApplicationId applicationId = Apps.toAppID(id); + containers = new ArrayList(); + Set keySet = appHistoryReader + .getApplicationAttempts(applicationId).keySet(); + for (ApplicationAttemptId applicationAttemptId : keySet) { + containers.addAll(appHistoryReader.getContainers(applicationAttemptId) + .values()); + } + } catch (IOException e) { + html.p()._("Sorry, Failed to get containers for app id:" + id) + ._(); + return; + } + renderContainersTable(html, containers); + } + + protected void renderContainersTable(Block html, + Collection containers) { + TBODY> tbody = html. + h2("Containers"). + table("#appContainers"). + thead(). + tr(). + th(".id", "Container ID"). + th(".name", "Allocated Resource"). + th("Assigned Node"). + th("Priority"). + th("Start Time"). + th("Finish Time"). + th("Diagnostics Info"). + th(".state", "Final Container Status")._()._(). + tbody(); + + StringBuilder containersTableData = new StringBuilder("[\n"); + for (ContainerHistoryData containerHistoryData : containers) { + String containerId = String.valueOf(containerHistoryData.getContainerId()); + containersTableData.append("[\"") + .append("").append(containerId).append("\",\"") + .append(containerHistoryData.getAllocatedResource()).append("\",\"") + .append(String.valueOf(containerHistoryData.getAssignedNode())).append("\",\"") + .append(containerHistoryData.getPriority()).append("\",\"") + .append(dateFormat.format(new Date(containerHistoryData.getStartTime()))).append("\",\"") + .append(dateFormat.format(new Date(containerHistoryData.getFinishTime()))).append("\",\"") + .append(containerHistoryData.getDiagnosticsInfo()).append("\",\"") + .append(containerHistoryData.getFinalContainerStatus()).append("\"],\n"); + } + + // Remove the last comma and close off the array of arrays + if (containersTableData.charAt(containersTableData.length() - 2) == ',') { + containersTableData.delete(containersTableData.length() - 2, + containersTableData.length() - 1); + } + containersTableData.append("]"); + html.script().$type("text/javascript")._( + "var appContainers=" + containersTableData)._(); + tbody._(). + tfoot(). + tr(). + th().input("search_init").$type(InputType.text).$name("container_id").$value("Container ID")._()._(). + th().input("search_init").$type(InputType.text).$name("allocated_resource").$value("Allocated Resource")._()._(). + th().input("search_init").$type(InputType.text).$name("assigned_node").$value("Assigned Node")._()._(). + th().input("search_init").$type(InputType.text).$name("priority").$value("Priority")._()._(). + th().input("search_init").$type(InputType.text).$name("start_time").$value("Start Time")._()._(). + th().input("search_init").$type(InputType.text).$name("finish_time").$value("Finish Time")._()._(). + th().input("search_init").$type(InputType.text).$name("diagnostics").$value("Diagnostics")._()._(). + th().input("search_init").$type(InputType.text).$name("final_container_status").$value("Final Container Status")._()._(). + _()._()._(); + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainersPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainersPage.java new file mode 100644 index 0000000..4f3394f --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSAppContainersPage.java @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.join; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES_ID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.postInitID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.tableInit; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSAppContainersPage extends AHSView { + + @Override + protected void preHead(Page.HTML<_> html) { + commonPreHead(html); + set(DATATABLES_ID, "appContainers"); + setTableStyles(html, "appContainers", ".queue {width:6em}", + ".ui {width:8em}"); + set(initID(DATATABLES, "appContainers"), appContainersTableInit()); + set(postInitID(DATATABLES, "appContainers"), appContainerssPostTableInit()); + initTitle(); + } + + protected void initTitle() { + String appId = $(YarnWebParams.APPLICATION_ID); + set(TITLE, appId.isEmpty() ? "Bad request: missing application ID" : join( + "YARN Application ", $(YarnWebParams.APPLICATION_ID), " Containers")); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:1}"); + } + + private String appContainerssPostTableInit() { + return "var asInitVals = new Array();\n" + + "$('tfoot input').keyup( function () \n{"+ + " appContainersDataTable.fnFilter( this.value, $('tfoot input').index(this) );\n"+ + "} );\n"+ + "$('tfoot input').each( function (i) {\n"+ + " asInitVals[i] = this.value;\n"+ + "} );\n"+ + "$('tfoot input').focus( function () {\n"+ + " if ( this.className == 'search_init' )\n"+ + " {\n"+ + " this.className = '';\n"+ + " this.value = '';\n"+ + " }\n"+ + "} );\n"+ + "$('tfoot input').blur( function (i) {\n"+ + " if ( this.value == '' )\n"+ + " {\n"+ + " this.className = 'search_init';\n"+ + " this.value = asInitVals[$('tfoot input').index(this)];\n"+ + " }\n"+ + "} );\n"; + } + + private String appContainersTableInit() { + return tableInit(). + append(", 'aaData': appContainers"). + append(", bDeferRender: true"). + append(", bProcessing: true"). + + // Sort by id upon page load + append(", aaSorting: [[0, 'desc']]"). + append(", aoColumnDefs:["). + append("]}"). + toString(); + } + + @Override + protected Class content() { + return AHSAppContainersBlock.class; + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSApplicationBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSApplicationBlock.java new file mode 100644 index 0000000..b5837a9 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSApplicationBlock.java @@ -0,0 +1,134 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._EVEN; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._ODD; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH; + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; + +import org.apache.hadoop.util.StringUtils; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationAttemptHistoryData; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationHistoryData; +import org.apache.hadoop.yarn.util.Apps; +import org.apache.hadoop.yarn.util.Times; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.DIV; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; +import org.apache.hadoop.yarn.webapp.view.InfoBlock; + +import com.google.inject.Inject; + +public class AHSApplicationBlock extends HtmlBlock { + + private final ApplicationHistoryReader appHistoryReader; + + @Inject + public AHSApplicationBlock(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + protected void render(Block html) { + String appid = $(YarnWebParams.APPLICATION_ID); + if (appid.isEmpty()) { + html. + p()._("Sorry, can't do anything without a App Id.")._(); + return; + } + ApplicationId applicationId = Apps.toAppID(appid); + ApplicationHistoryData applicationHistoryData; + try { + applicationHistoryData = appHistoryReader + .getApplication(applicationId); + } catch (IOException e) { + return; + } + if (applicationHistoryData == null) { + html. + p()._("Sorry, ", applicationId, " not found.")._(); + return; + } + Collection applicationAttempts; + try { + applicationAttempts = appHistoryReader + .getApplicationAttempts(applicationId).values(); + } catch (IOException e) { + html.p()._("Sorry, Failed to read attempts for App Id:" + applicationId) + ._(); + return; + } + info("Application Overview"). + _("Application Name:", applicationHistoryData.getApplicationName()). + _("Type:", applicationHistoryData.getApplicationType()). + _("User Name:", applicationHistoryData.getApplicationName()). + _("Queue:", applicationHistoryData.getQueue()). + _("Submitted:", new Date(applicationHistoryData.getSubmitTime())). + _("Started:", new Date(applicationHistoryData.getStartTime())). + _("Finished:", new Date(applicationHistoryData.getFinishTime())). + _("Final Status:", applicationHistoryData.getFinalApplicationStatus()). + _("Diagnostics:", applicationHistoryData.getDiagnosticsInfo()). + _("Elapsed:", StringUtils.formatTime( + Times.elapsed(applicationHistoryData.getStartTime(), applicationHistoryData.getFinishTime(), false))); + + DIV div = html._(InfoBlock.class).div(_INFO_WRAP); + + + String amString = + applicationAttempts.size() >1 ? "ApplicationMasters" : "ApplicationMaster"; + + TABLE> table = div.table("#attempts"); + table. + tr(). + th(amString)._(). + tr(). + th(_TH, "Attempt Number"). + th(_TH, "Host"). + th(_TH, "RPC Port"). + th(_TH, "Tracking URL"). + th(_TH, "Diagnostics Info"). + th(_TH, "Final Application Status"). + th(_TH, "Master Container Id"). + _(); + + boolean odd = false; + for (ApplicationAttemptHistoryData attemptData : applicationAttempts) { + ApplicationAttemptId appAttemptId = attemptData.getApplicationAttemptId(); + table.tr((odd = !odd) ? _ODD : _EVEN). + td().a(url("appattempt", appAttemptId.toString()), String.valueOf(appAttemptId.getAttemptId()))._(). + td(attemptData.getHost()). + td(String.valueOf(attemptData.getRPCPort())). + td(attemptData.getTrackingURL()). + td(attemptData.getDiagnosticsInfo()). + td(String.valueOf(attemptData.getFinalApplicationStatus())). + td().a(url("container", attemptData.getMasterContainerId().toString()), + String.valueOf(attemptData.getMasterContainerId()))._()._(); + } + table._(); + div._(); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSApplicationPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSApplicationPage.java new file mode 100644 index 0000000..06823b7 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSApplicationPage.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.join; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSApplicationPage extends AHSView { + + @Override + protected void preHead(Page.HTML<_> html) { + String appId = $(YarnWebParams.APPLICATION_ID); + set(TITLE, appId.isEmpty() ? "Bad request: missing application ID" : join( + "YARN Application ", $(YarnWebParams.APPLICATION_ID))); + commonPreHead(html); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:1}"); + } + + @Override + protected Class content() { + return AHSApplicationBlock.class; + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSNavBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSNavBlock.java new file mode 100644 index 0000000..566977b --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSNavBlock.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.util.ConverterUtils; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.DIV; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; + +public class AHSNavBlock extends HtmlBlock { + + @Override + protected void render(Block html) { + DIV nav = html. + div("#nav"). + h3("Application History"). + ul(). + li().a(url("about"), "About")._(). + li().a("/applicationhistory", "Applications")._()._(); + String appId = $(YarnWebParams.APPLICATION_ID); + String appAttemptId = $(YarnWebParams.APPLICATION_ATTEMPT_ID); + String containerId = $(YarnWebParams.CONTAINER_ID); + if (appAttemptId.isEmpty() == false) { + appId = ConverterUtils.toApplicationAttemptId(appAttemptId) + .getApplicationId().toString(); + } else if (containerId.isEmpty() == false) { + ContainerId contId = ConverterUtils.toContainerId(containerId); + appAttemptId = contId.getApplicationAttemptId().toString(); + appId = contId.getApplicationAttemptId().getApplicationId().toString(); + } + if (appId.isEmpty() == false) { + nav. + h3("Application"). + ul(). + li().a(url("application", appId), "Overview")._(). + li().a(url("appattempts", appId), "Attempts")._(). + li().a(url("appcontainers", appId), "Containers")._()._(); + } + if (appAttemptId.isEmpty() == false) { + nav. + h3("Application Attempt"). + ul(). + li().a(url("appattempt", appAttemptId), "Overview")._(). + li().a(url("appattemptcontainers", appAttemptId), "Containers")._()._(); + } + nav. + h3("Tools"). + ul(). + li().a("/conf", "Configuration")._(). + li().a("/stacks", "Thread dump")._(). + li().a("/logs", "Logs")._(). + li().a("/metrics", "Metrics")._()._()._(); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSView.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSView.java new file mode 100644 index 0000000..9b66af7 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSView.java @@ -0,0 +1,95 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.ACCORDION_ID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES_ID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.postInitID; +import static org.apache.hadoop.yarn.webapp.view.JQueryUI.tableInit; + +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.view.TwoColumnLayout; + +public class AHSView extends TwoColumnLayout { + + @Override + protected void preHead(Page.HTML<_> html) { + commonPreHead(html); + set(DATATABLES_ID, "appsTableData"); + setTableStyles(html, "appsTableData", ".queue {width:6em}", + ".ui {width:8em}"); + set(initID(DATATABLES, "appsTableData"), appsTableInit()); + set(postInitID(DATATABLES, "appsTableData"), appsPostTableInit()); + setTitle("Application History"); + } + + protected void commonPreHead(Page.HTML<_> html) { + set(ACCORDION_ID, "nav"); + set(initID(ACCORDION, "nav"), "{autoHeight:false, active:0}"); + } + + @Override + protected Class nav() { + return AHSNavBlock.class; + } + + @Override + protected Class content() { + return ApplicationHistoryView.class; + } + + private String appsPostTableInit() { + return "var asInitVals = new Array();\n" + + "$('tfoot input').keyup( function () \n{"+ + " appsTableDataDataTable.fnFilter( this.value, $('tfoot input').index(this) );\n"+ + "} );\n"+ + "$('tfoot input').each( function (i) {\n"+ + " asInitVals[i] = this.value;\n"+ + "} );\n"+ + "$('tfoot input').focus( function () {\n"+ + " if ( this.className == 'search_init' )\n"+ + " {\n"+ + " this.className = '';\n"+ + " this.value = '';\n"+ + " }\n"+ + "} );\n"+ + "$('tfoot input').blur( function (i) {\n"+ + " if ( this.value == '' )\n"+ + " {\n"+ + " this.className = 'search_init';\n"+ + " this.value = asInitVals[$('tfoot input').index(this)];\n"+ + " }\n"+ + "} );\n"; + } + + private String appsTableInit() { + return tableInit(). + append(", 'aaData': appsTableData"). + append(", bDeferRender: true"). + append(", bProcessing: true"). + + // Sort by id upon page load + append(", aaSorting: [[0, 'desc']]"). + append(", aoColumnDefs:["). + append("]}"). + toString(); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSWebApp.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSWebApp.java new file mode 100644 index 0000000..5816c44 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/AHSWebApp.java @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.util.StringHelper.pajoin; + +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.webapp.GenericExceptionHandler; +import org.apache.hadoop.yarn.webapp.WebApp; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class AHSWebApp extends WebApp implements YarnWebParams { + + private final ApplicationHistoryReader appHistoryReader; + + public AHSWebApp(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + public void setup() { +// bind(AHSWebServices.class); + bind(GenericExceptionHandler.class); +// bind(AHSJAXBContextResolver.class); + bind(ApplicationHistoryReader.class).toInstance(this.appHistoryReader); + route("/", ApplicationHistoryController.class, "applicationHistory"); + route("/about", ApplicationHistoryController.class, "about"); + route("/applicationhistory", ApplicationHistoryController.class, + "applicationHistory"); + route(pajoin("/application", YarnWebParams.APPLICATION_ID), + ApplicationHistoryController.class, "application"); + route(pajoin("/appattempts", YarnWebParams.APPLICATION_ID), + ApplicationHistoryController.class, "appAttempts"); + route(pajoin("/appattempt", YarnWebParams.APPLICATION_ATTEMPT_ID), + ApplicationHistoryController.class, "appAttempt"); + route(pajoin("/appcontainers", YarnWebParams.APPLICATION_ID), + ApplicationHistoryController.class, "appContainers"); + route( + pajoin("/appattemptcontainers", YarnWebParams.APPLICATION_ATTEMPT_ID), + ApplicationHistoryController.class, "appAttemptContainers"); + route(pajoin("/container", YarnWebParams.CONTAINER_ID), + ApplicationHistoryController.class, "container"); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/ApplicationHistoryController.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/ApplicationHistoryController.java new file mode 100644 index 0000000..ceb27f2 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/ApplicationHistoryController.java @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import org.apache.hadoop.yarn.webapp.Controller; +import org.apache.hadoop.yarn.webapp.YarnWebParams; + +public class ApplicationHistoryController extends Controller implements + YarnWebParams { + + public void applicationHistory() { + render(ApplicationHistoryPage.class); + } + + public void about() { + render(AHSAboutPage.class); + } + + public void application() { + render(AHSApplicationPage.class); + } + + public void appAttempts() { + render(AHSAppAttemptsPage.class); + } + + public void appAttempt() { + render(AHSAppAttemptPage.class); + } + + public void appContainers() { + render(AHSAppContainersPage.class); + } + + public void appAttemptContainers() { + render(AHSAppAttemptContainersPage.class); + } + + public void container() { + render(AHSAppContainerPage.class); + } + + @Override + public void index() { + setTitle("ApplicationHistory"); + } + + +} \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/ApplicationHistoryPage.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/ApplicationHistoryPage.java new file mode 100644 index 0000000..fe81c19 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/ApplicationHistoryPage.java @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import java.util.Collection; +import java.util.Date; +import java.io.IOException; +import java.text.SimpleDateFormat; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationHistoryData; +import org.apache.hadoop.yarn.webapp.SubView; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TBODY; +import org.apache.hadoop.yarn.webapp.hamlet.HamletSpec.InputType; +import org.apache.hadoop.yarn.webapp.view.HtmlBlock; + +import com.google.inject.Inject; + +public class ApplicationHistoryPage extends AHSView { + + @Override + protected Class content() { + return ApplicationHistoryView.class; + } +} + +class ApplicationHistoryView extends HtmlBlock { + final SimpleDateFormat dateFormat = new SimpleDateFormat( + "yyyy.MM.dd HH:mm:ss z"); + private final ApplicationHistoryReader appHistoryReader; + + @Inject + ApplicationHistoryView(ApplicationHistoryReader appHistoryReader) { + this.appHistoryReader = appHistoryReader; + } + + @Override + protected void render(Block html) { + Collection values; + try { + values = appHistoryReader.getAllApplications().values(); + } catch (IOException e) { + String message = "Failed to read applications."; + LOG.error(message, e); + html.p()._(message)._(); + return; + } + TBODY> tbody = html. + h2("Completed Applications"). + table("#appsTableData"). + thead(). + tr(). + th(".id", "Application ID"). + th(".name", "Name"). + th("Application Type"). + th("User"). + th("Queue"). + th("Submit Time"). + th("Start Time"). + th("Finish Time"). + th("Diagnostics"). + th(".state", "Final Application Status")._()._(). + tbody(); + + StringBuilder appsTableData = new StringBuilder("[\n"); + for (ApplicationHistoryData appHistoryData : values) { + String appId = String.valueOf(appHistoryData.getApplicationId()); + appsTableData.append("[\"") + .append("").append(appId).append("\",\"") + .append(StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(appHistoryData.getApplicationName()))).append("\",\"") + .append(appHistoryData.getApplicationType()).append("\",\"") + .append(StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(appHistoryData.getUser()))).append("\",\"") + .append(StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(appHistoryData.getQueue()))).append("\",\"") + .append(dateFormat.format(new Date(appHistoryData.getSubmitTime()))).append("\",\"") + .append(dateFormat.format(new Date(appHistoryData.getStartTime()))).append("\",\"") + .append(dateFormat.format(new Date(appHistoryData.getFinishTime()))).append("\",\"") + .append(appHistoryData.getDiagnosticsInfo()).append("\",\"") + .append(appHistoryData.getFinalApplicationStatus()).append("\"],\n"); + } + + // Remove the last comma and close off the array of arrays + if (appsTableData.charAt(appsTableData.length() - 2) == ',') { + appsTableData.delete(appsTableData.length() - 2, + appsTableData.length() - 1); + } + appsTableData.append("]"); + html.script().$type("text/javascript")._( + "var appsTableData=" + appsTableData)._(); + tbody._(). + tfoot(). + tr(). + th().input("search_init").$type(InputType.text).$name("application_id").$value("Application ID")._()._(). + th().input("search_init").$type(InputType.text).$name("name").$value("Name")._()._(). + th().input("search_init").$type(InputType.text).$name("application_type").$value("Application Type")._()._(). + th().input("search_init").$type(InputType.text).$name("user").$value("User")._()._(). + th().input("search_init").$type(InputType.text).$name("queue").$value("Queue")._()._(). + th().input("search_init").$type(InputType.text).$name("submit_time").$value("Submit Time")._()._(). + th().input("search_init").$type(InputType.text).$name("start_time").$value("Start Time")._()._(). + th().input("search_init").$type(InputType.text).$name("finish_time").$value("Finish Time")._()._(). + th().input("search_init").$type(InputType.text).$name("diagnostics").$value("Diagnostics")._()._() + .th().input("search_init").$type(InputType.text).$name("final_status").$value("Final Application Status") + ._() + ._()._()._()._(); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/dao/AHSInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/dao/AHSInfo.java new file mode 100644 index 0000000..29acc07 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/dao/AHSInfo.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.util.VersionInfo; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryServer; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class AHSInfo { + + protected long startedOn; + protected String hadoopVersion; + protected String hadoopBuildVersion; + protected String hadoopVersionBuiltOn; + + public AHSInfo() { + this.startedOn = ApplicationHistoryServer.appHistoryServerTimeStamp; + this.hadoopVersion = VersionInfo.getVersion(); + this.hadoopBuildVersion = VersionInfo.getBuildVersion(); + this.hadoopVersionBuiltOn = VersionInfo.getDate(); + } + + public String getHadoopVersion() { + return this.hadoopVersion; + } + + public String getHadoopBuildVersion() { + return this.hadoopBuildVersion; + } + + public String getHadoopVersionBuiltOn() { + return this.hadoopVersionBuiltOn; + } + + public long getStartedOn() { + return this.startedOn; + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/MockApplicationHistoryReader.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/MockApplicationHistoryReader.java new file mode 100644 index 0000000..8cec5ae --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/MockApplicationHistoryReader.java @@ -0,0 +1,151 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; +import org.apache.hadoop.yarn.api.records.NodeId; +import org.apache.hadoop.yarn.api.records.Priority; +import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationAttemptHistoryData; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ApplicationHistoryData; +import org.apache.hadoop.yarn.server.applicationhistoryservice.records.ContainerHistoryData; +import org.apache.hadoop.yarn.util.Records; + +public class MockApplicationHistoryReader implements ApplicationHistoryReader { + private Map apps = + new HashMap(); + private Map> attempts = + new HashMap>(); + private Map> containers = + new HashMap>(); + + public MockApplicationHistoryReader(int noOfApps) throws IOException { + long timeStamp = System.currentTimeMillis(); + for (int i = 0; i < noOfApps; i++) { + ApplicationId applicationId = ApplicationId.newInstance(timeStamp, i); + apps.put(applicationId, getApplication(applicationId)); + } + } + + public MockApplicationHistoryReader(int noOfApps, int noOfAttempts) + throws IOException { + this(noOfApps); + for (ApplicationId appId : apps.keySet()) { + Map appAttempts = + new HashMap(); + for (int i = 0; i < noOfAttempts; i++) { + ApplicationAttemptId attemptId = + ApplicationAttemptId.newInstance(appId, i); + appAttempts.put(attemptId, getApplicationAttempt(attemptId)); + } + attempts.put(appId, appAttempts); + } + } + + public MockApplicationHistoryReader(int noOfApps, int noOfAttempts, + int noOfContainers) throws IOException { + this(noOfApps, noOfAttempts); + for (ApplicationId appId : attempts.keySet()) { + for (ApplicationAttemptId attemptId : attempts.get(appId).keySet()) { + Map attemptContainers = + new HashMap(); + for (int i = 0; i < noOfContainers; i++) { + ContainerId containerId = ContainerId.newInstance(attemptId, i); + attemptContainers.put(containerId, getContainer(containerId)); + } + containers.put(attemptId, attemptContainers); + } + } + } + + @Override + public ContainerHistoryData getAMContainer(ApplicationAttemptId appAttemptId) + throws IOException { + ContainerHistoryData data = Records.newRecord(ContainerHistoryData.class); + data.setContainerId(ContainerId.newInstance(appAttemptId, 0)); + data.setAssignedNode(NodeId.newInstance("abc", 10)); + data.setPriority(Priority.newInstance(10)); + data.setAllocatedResource(Resource.newInstance(1024, 1)); + return data; + } + + @Override + public Map getAllApplications() + throws IOException { + return apps; + } + + @Override + public ApplicationHistoryData getApplication(ApplicationId appId) + throws IOException { + ApplicationHistoryData appHistoryData = + Records.newRecord(ApplicationHistoryData.class); + appHistoryData.setApplicationId(appId); + appHistoryData.setQueue("Testqueue"); + appHistoryData.setUser("TestUser"); + return appHistoryData; + } + + @Override + public ApplicationAttemptHistoryData getApplicationAttempt( + ApplicationAttemptId appAttemptId) throws IOException { + ApplicationAttemptHistoryData data = + Records.newRecord(ApplicationAttemptHistoryData.class); + data.setApplicationAttemptId(appAttemptId); + ContainerId containerId = ContainerId.newInstance(appAttemptId, 0); + data.setMasterContainerId(containerId); + data.setDiagnosticsInfo("Test Diagnostic info"); + data.setHost("TestHost"); + data.setRPCPort(123); + data.setFinalApplicationStatus(FinalApplicationStatus.SUCCEEDED); + data.setTrackingURL("http://trackingurl.com"); + return data; + } + + @Override + public Map getApplicationAttempts( + ApplicationId appId) throws IOException { + return attempts.get(appId); + } + + @Override + public ContainerHistoryData getContainer(ContainerId containerId) + throws IOException { + ContainerHistoryData data = Records.newRecord(ContainerHistoryData.class); + data.setContainerId(containerId); + data.setAssignedNode(NodeId.newInstance("abc", 10)); + data.setPriority(Priority.newInstance(10)); + data.setAllocatedResource(Resource.newInstance(1024, 1)); + return data; + } + + @Override + public Map getContainers( + ApplicationAttemptId appAttemptId) throws IOException { + return containers.get(appAttemptId); + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebApp.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebApp.java new file mode 100644 index 0000000..19f264a --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebApp.java @@ -0,0 +1,207 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.yarn.server.applicationhistoryservice.webapp; + +import static org.apache.hadoop.yarn.webapp.Params.TITLE; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.atLeastOnce; + +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.server.applicationhistoryservice.ApplicationHistoryReader; +import org.apache.hadoop.yarn.webapp.YarnWebParams; +import org.apache.hadoop.yarn.webapp.test.WebAppTests; +import org.junit.Test; + +import com.google.inject.Injector; + +public class TestAHSWebApp { + private final static Map EMPTY_MAP = + new HashMap(); + + @Test + public void testAppControllerIndex() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(0); + Injector injector = + WebAppTests.createMockInjector(ApplicationHistoryReader.class, + mockAppHSReader); + ApplicationHistoryController controller = + injector.getInstance(ApplicationHistoryController.class); + controller.index(); + assertEquals("ApplicationHistory", controller.get(TITLE, "unknown")); + } + + @Test + public void testApplicationsPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(5); + Injector injector = + WebAppTests.testPage(ApplicationHistoryPage.class, + ApplicationHistoryReader.class, mockAppHSReader, + new HashMap()); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Completed Applications"); + } + + @Test + public void testApplicationPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(1); + Injector injector = + WebAppTests.testPage(AHSApplicationPage.class, + ApplicationHistoryReader.class, mockAppHSReader, EMPTY_MAP); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Sorry, can't do anything without a App Id."); + + HashMap params = new HashMap(); + ApplicationId applicationId = + mockAppHSReader.getAllApplications().values().iterator().next() + .getApplicationId(); + params.put(YarnWebParams.APPLICATION_ID, applicationId.toString()); + injector = + WebAppTests.testPage(AHSApplicationPage.class, + ApplicationHistoryReader.class, mockAppHSReader, params); + spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw, atLeastOnce()).write("YARN Application " + applicationId); + } + + @Test + public void testAppAttemptsPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(1, 4); + Injector injector = + WebAppTests.testPage(AHSAppAttemptsPage.class, + ApplicationHistoryReader.class, mockAppHSReader, EMPTY_MAP); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Sorry, can't do anything without a App Id."); + + HashMap params = new HashMap(); + ApplicationId applicationId = + mockAppHSReader.getAllApplications().values().iterator().next() + .getApplicationId(); + params.put(YarnWebParams.APPLICATION_ID, applicationId.toString()); + injector = + WebAppTests.testPage(AHSAppAttemptsPage.class, + ApplicationHistoryReader.class, mockAppHSReader, params); + spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw, atLeastOnce()).write("YARN Application " + applicationId); + } + + @Test + public void testAppAttemptPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(1, 1); + Injector injector = WebAppTests.testPage(AHSAppAttemptPage.class, + ApplicationHistoryReader.class, mockAppHSReader, EMPTY_MAP); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Sorry, can't do anything without a App Attempt Id."); + + HashMap params = new HashMap(); + ApplicationId appId = + mockAppHSReader.getAllApplications().values().iterator().next() + .getApplicationId(); + ApplicationAttemptId applicationAttemptId = mockAppHSReader + .getApplicationAttempts(appId).values().iterator().next() + .getApplicationAttemptId(); + params.put(YarnWebParams.APPLICATION_ATTEMPT_ID, applicationAttemptId.toString()); + injector = WebAppTests.testPage(AHSAppAttemptPage.class, + ApplicationHistoryReader.class, mockAppHSReader, params); + spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw, atLeastOnce()).write("YARN Application " + applicationAttemptId); + } + + @Test + public void testAppContainersPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(1, 2, 10); + Injector injector = + WebAppTests.testPage(AHSAppContainersPage.class, + ApplicationHistoryReader.class, mockAppHSReader, EMPTY_MAP); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Sorry, can't do anything without a App Id."); + + HashMap params = new HashMap(); + params.put(YarnWebParams.APPLICATION_ID, mockAppHSReader + .getAllApplications().values().iterator().next().getApplicationId() + .toString()); + injector = + WebAppTests.testPage(AHSAppContainersPage.class, + ApplicationHistoryReader.class, mockAppHSReader, params); + spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw, atLeastOnce()).write("Containers"); + } + + @Test + public void testAppAttemptContainersPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(1, 1, 10); + Injector injector = + WebAppTests.testPage(AHSAppAttemptContainersPage.class, + ApplicationHistoryReader.class, mockAppHSReader, EMPTY_MAP); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Sorry, can't do anything without a AppAttempt Id."); + + HashMap params = new HashMap(); + ApplicationId appId = + mockAppHSReader.getAllApplications().values().iterator().next() + .getApplicationId(); + params.put(YarnWebParams.APPLICATION_ATTEMPT_ID, mockAppHSReader + .getApplicationAttempts(appId).values().iterator().next() + .getApplicationAttemptId().toString()); + injector = + WebAppTests.testPage(AHSAppAttemptContainersPage.class, + ApplicationHistoryReader.class, mockAppHSReader, params); + spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw, atLeastOnce()).write("Containers"); + } + + @Test + public void testAppContainerPage() throws Throwable { + ApplicationHistoryReader mockAppHSReader = + new MockApplicationHistoryReader(1, 1, 1); + Injector injector = + WebAppTests.testPage(AHSAppContainerPage.class, + ApplicationHistoryReader.class, mockAppHSReader, + new HashMap()); + PrintWriter spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw).write("Sorry, can't do anything without a Container Id."); + + HashMap params = new HashMap(); + ApplicationId appId = + mockAppHSReader.getAllApplications().values().iterator().next() + .getApplicationId(); + ApplicationAttemptId attemptId = + mockAppHSReader.getApplicationAttempts(appId).values().iterator() + .next().getApplicationAttemptId(); + String containerId = + mockAppHSReader.getContainers(attemptId).values().iterator().next() + .getContainerId().toString(); + params.put(YarnWebParams.CONTAINER_ID, containerId); + injector = + WebAppTests.testPage(AHSAppContainerPage.class, + ApplicationHistoryReader.class, mockAppHSReader, params); + spyPw = WebAppTests.getPrintWriter(injector); + verify(spyPw, atLeastOnce()).write("YARN Application " + containerId); + } +}