diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java index 2ab5568..7a76433 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java @@ -62,6 +62,7 @@ protected ApplicationBaseProtocol appBaseProt; protected Configuration conf; protected ApplicationId appID = null; + protected UserGroupInformation callerUGI; @Inject protected AppBlock(ApplicationBaseProtocol appBaseProt, ViewContext ctx, @@ -87,7 +88,7 @@ protected void render(Block html) { return; } - UserGroupInformation callerUGI = getCallerUGI(); + callerUGI = getCallerUGI(); ApplicationReport appReport = null; try { final GetApplicationReportRequest request = @@ -211,6 +212,42 @@ public ApplicationReport run() throws Exception { html._(InfoBlock.class); // Application Attempt Table + createApplicationAttemptTable(html, attempts); + } + + private String clarifyAppState(YarnApplicationState state) { + String ret = state.toString(); + switch (state) { + case NEW: + return ret + ": waiting for application to be initialized"; + case NEW_SAVING: + return ret + ": waiting for application to be persisted in state-store."; + case SUBMITTED: + return ret + ": waiting for application to be accepted by scheduler."; + case ACCEPTED: + return ret + ": waiting for AM container to be allocated, launched and" + + " register with RM."; + case RUNNING: + return ret + ": AM has registered with RM and started running."; + default: + return ret; + } + } + + private String clairfyAppFinalStatus(FinalApplicationStatus status) { + if (status == FinalApplicationStatus.UNDEFINED) { + return "Application has not completed yet."; + } + return status.toString(); + } + + // The preemption metrics only need to be shown in RM WebUI + protected void createApplicationMetricsTable(Block html) { + + } + + protected void createApplicationAttemptTable(Block html, + Collection attempts) { TBODY> tbody = html.table("#attempts").thead().tr().th(".id", "Attempt ID") .th(".started", "Started").th(".node", "Node").th(".logs", "Logs") @@ -229,20 +266,21 @@ public ApplicationReport run() throws Exception { containerReport = appBaseProt.getContainerReport(request).getContainerReport(); } else { - containerReport = callerUGI.doAs( - new PrivilegedExceptionAction () { - @Override - public ContainerReport run() throws Exception { - ContainerReport report = null; - try { - report = appBaseProt.getContainerReport(request) - .getContainerReport(); - } catch (ContainerNotFoundException ex) { - LOG.warn(ex.getMessage()); - } - return report; - } - }); + containerReport = + callerUGI.doAs(new PrivilegedExceptionAction() { + @Override + public ContainerReport run() throws Exception { + ContainerReport report = null; + try { + report = + appBaseProt.getContainerReport(request) + .getContainerReport(); + } catch (ContainerNotFoundException ex) { + LOG.warn(ex.getMessage()); + } + return report; + } + }); } } catch (Exception e) { String message = @@ -271,7 +309,8 @@ public ContainerReport run() throws Exception { .append("\",\"") - .append(nodeLink == null ? "N/A" : StringEscapeUtils + .append( + nodeLink == null ? "N/A" : StringEscapeUtils .escapeJavaScript(StringEscapeUtils.escapeHtml(nodeLink))) .append("\",\"") @@ -287,35 +326,4 @@ public ContainerReport run() throws Exception { tbody._()._(); } - - private String clarifyAppState(YarnApplicationState state) { - String ret = state.toString(); - switch (state) { - case NEW: - return ret + ": waiting for application to be initialized"; - case NEW_SAVING: - return ret + ": waiting for application to be persisted in state-store."; - case SUBMITTED: - return ret + ": waiting for application to be accepted by scheduler."; - case ACCEPTED: - return ret + ": waiting for AM container to be allocated, launched and" - + " register with RM."; - case RUNNING: - return ret + ": AM has registered with RM and started running."; - default: - return ret; - } - } - - private String clairfyAppFinalStatus(FinalApplicationStatus status) { - if (status == FinalApplicationStatus.UNDEFINED) { - return "Application has not completed yet."; - } - return status.toString(); - } - - // The preemption metrics only need to be shown in RM WebUI - protected void createApplicationMetricsTable(Block html) { - - } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMAppBlock.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMAppBlock.java index 64c5747..e986cab 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMAppBlock.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMAppBlock.java @@ -20,16 +20,25 @@ import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; +import java.util.Collection; + +import org.apache.commons.lang.StringEscapeUtils; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport; import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppMetrics; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptInfo; import org.apache.hadoop.yarn.server.webapp.AppBlock; import org.apache.hadoop.yarn.util.resource.Resources; 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.hamlet.Hamlet.TBODY; +import org.apache.hadoop.yarn.webapp.util.WebAppUtils; import org.apache.hadoop.yarn.webapp.view.InfoBlock; import com.google.inject.Inject; @@ -37,11 +46,13 @@ public class RMAppBlock extends AppBlock{ private final ResourceManager rm; + private final Configuration conf; @Inject RMAppBlock(ViewContext ctx, Configuration conf, ResourceManager rm) { super(rm.getClientRMService(), ctx, conf); this.rm = rm; + this.conf = conf; } @Override @@ -91,4 +102,57 @@ protected void createApplicationMetricsTable(Block html){ appMetrics == null ? "N/A" : appMetrics.getVcoreSeconds())); pdiv._(); } + + @Override + protected void createApplicationAttemptTable(Block html, + Collection attempts) { + TBODY> tbody = + html.table("#attempts").thead().tr().th(".id", "Attempt ID") + .th(".started", "Started").th(".node", "Node").th(".logs", "Logs") + ._()._().tbody(); + RMApp rmApp = this.rm.getRMContext().getRMApps().get(this.appID); + if (rmApp == null) { + return; + } + StringBuilder attemptsTableData = new StringBuilder("[\n"); + for (final ApplicationAttemptReport appAttemptReport : attempts) { + RMAppAttempt rmAppAttempt = + rmApp.getRMAppAttempt(appAttemptReport.getApplicationAttemptId()); + if (rmAppAttempt == null) { + continue; + } + AppAttemptInfo attemptInfo = + new AppAttemptInfo(rmAppAttempt, rmApp.getUser()); + String nodeLink = attemptInfo.getNodeHttpAddress(); + if (nodeLink != null) { + nodeLink = WebAppUtils.getHttpSchemePrefix(conf) + nodeLink; + } + String logsLink = attemptInfo.getLogsLink(); + attemptsTableData + .append("[\"") + .append(String.valueOf(rmAppAttempt.getAppAttemptId())) + .append("\",\"") + .append(attemptInfo.getStartTime()) + .append("\",\"") + .append( + nodeLink == null ? "N/A" : StringEscapeUtils + .escapeJavaScript(StringEscapeUtils.escapeHtml(nodeLink))) + .append("\",\"") + .append(logsLink == null ? "N/A" : "Logs").append("\"],\n"); + } + if (attemptsTableData.charAt(attemptsTableData.length() - 2) == ',') { + attemptsTableData.delete(attemptsTableData.length() - 2, + attemptsTableData.length() - 1); + } + attemptsTableData.append("]"); + html.script().$type("text/javascript") + ._("var attemptsTableData=" + attemptsTableData)._(); + + tbody._()._(); + } }