YARN-3248. Display count of nodes blacklisted by apps in the web UI.

Contributed by Varun Vasudev

(cherry picked from commit 4728bdfa15)
This commit is contained in:
Xuan 2015-04-01 04:19:18 -07:00
parent 80755edb7a
commit e26b6e55e9
14 changed files with 468 additions and 82 deletions

View File

@ -819,6 +819,9 @@ Release 2.7.0 - UNRELEASED
removing inconsistencies in the default values. (Junping Du and Karthik removing inconsistencies in the default values. (Junping Du and Karthik
Kambatla via vinodkv) Kambatla via vinodkv)
YARN-3248. Display count of nodes blacklisted by apps in the web UI.
(Varun Vasudev via xgong)
Release 2.6.0 - 2014-11-18 Release 2.6.0 - 2014-11-18
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -72,7 +72,7 @@ public class AppAttemptBlock extends HtmlBlock {
} }
UserGroupInformation callerUGI = getCallerUGI(); UserGroupInformation callerUGI = getCallerUGI();
ApplicationAttemptReport appAttemptReport = null; ApplicationAttemptReport appAttemptReport;
try { try {
final GetApplicationAttemptReportRequest request = final GetApplicationAttemptReportRequest request =
GetApplicationAttemptReportRequest.newInstance(appAttemptId); GetApplicationAttemptReportRequest.newInstance(appAttemptId);
@ -135,34 +135,7 @@ public class AppAttemptBlock extends HtmlBlock {
&& appAttempt.getRpcPort() < 65536) { && appAttempt.getRpcPort() < 65536) {
node = appAttempt.getHost() + ":" + appAttempt.getRpcPort(); node = appAttempt.getHost() + ":" + appAttempt.getRpcPort();
} }
info("Application Attempt Overview") generateOverview(appAttemptReport, containers, appAttempt, node);
._(
"Application Attempt State:",
appAttempt.getAppAttemptState() == null ? UNAVAILABLE : appAttempt
.getAppAttemptState())
._(
"AM Container:",
appAttempt.getAmContainerId() == null || containers == null
|| !hasAMContainer(appAttemptReport.getAMContainerId(), containers)
? null : root_url("container", appAttempt.getAmContainerId()),
String.valueOf(appAttempt.getAmContainerId()))
._("Node:", node)
._(
"Tracking URL:",
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl() == UNAVAILABLE ? null
: root_url(appAttempt.getTrackingUrl()),
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl() == UNAVAILABLE
? "Unassigned"
: appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FINISHED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FAILED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.KILLED
? "History" : "ApplicationMaster")
._("Diagnostics Info:", appAttempt.getDiagnosticsInfo() == null ?
"" : appAttempt.getDiagnosticsInfo());
if (exceptionWhenGetContainerReports) { if (exceptionWhenGetContainerReports) {
html html
@ -218,7 +191,40 @@ public class AppAttemptBlock extends HtmlBlock {
tbody._()._(); tbody._()._();
} }
private boolean hasAMContainer(ContainerId containerId, protected void generateOverview(ApplicationAttemptReport appAttemptReport,
Collection<ContainerReport> containers, AppAttemptInfo appAttempt,
String node) {
info("Application Attempt Overview")
._(
"Application Attempt State:",
appAttempt.getAppAttemptState() == null ? UNAVAILABLE : appAttempt
.getAppAttemptState())
._(
"AM Container:",
appAttempt.getAmContainerId() == null || containers == null
|| !hasAMContainer(appAttemptReport.getAMContainerId(), containers)
? null : root_url("container", appAttempt.getAmContainerId()),
String.valueOf(appAttempt.getAmContainerId()))
._("Node:", node)
._(
"Tracking URL:",
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl().equals(UNAVAILABLE) ? null
: root_url(appAttempt.getTrackingUrl()),
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl().equals(UNAVAILABLE)
? "Unassigned"
: appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FINISHED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FAILED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.KILLED
? "History" : "ApplicationMaster")
._(
"Diagnostics Info:",
appAttempt.getDiagnosticsInfo() == null ? "" : appAttempt
.getDiagnosticsInfo());
}
protected boolean hasAMContainer(ContainerId containerId,
Collection<ContainerReport> containers) { Collection<ContainerReport> containers) {
for (ContainerReport container : containers) { for (ContainerReport container : containers) {
if (containerId.equals(container.getContainerId())) { if (containerId.equals(container.getContainerId())) {

View File

@ -88,7 +88,7 @@ public class AppBlock extends HtmlBlock {
} }
UserGroupInformation callerUGI = getCallerUGI(); UserGroupInformation callerUGI = getCallerUGI();
ApplicationReport appReport = null; ApplicationReport appReport;
try { try {
final GetApplicationReportRequest request = final GetApplicationReportRequest request =
GetApplicationReportRequest.newInstance(appID); GetApplicationReportRequest.newInstance(appID);
@ -160,7 +160,8 @@ public class AppBlock extends HtmlBlock {
._("Application Type:", app.getType()) ._("Application Type:", app.getType())
._("Application Tags:", ._("Application Tags:",
app.getApplicationTags() == null ? "" : app.getApplicationTags()) app.getApplicationTags() == null ? "" : app.getApplicationTags())
._("YarnApplicationState:", ._(
"YarnApplicationState:",
app.getAppState() == null ? UNAVAILABLE : clarifyAppState(app app.getAppState() == null ? UNAVAILABLE : clarifyAppState(app
.getAppState())) .getAppState()))
._("FinalStatus Reported by AM:", ._("FinalStatus Reported by AM:",
@ -170,11 +171,14 @@ public class AppBlock extends HtmlBlock {
"Elapsed:", "Elapsed:",
StringUtils.formatTime(Times.elapsed(app.getStartedTime(), StringUtils.formatTime(Times.elapsed(app.getStartedTime(),
app.getFinishedTime()))) app.getFinishedTime())))
._("Tracking URL:", ._(
app.getTrackingUrl() == null || app.getTrackingUrl() == UNAVAILABLE "Tracking URL:",
? null : root_url(app.getTrackingUrl()), app.getTrackingUrl() == null
app.getTrackingUrl() == null || app.getTrackingUrl() == UNAVAILABLE || app.getTrackingUrl().equals(UNAVAILABLE) ? null : root_url(app
? "Unassigned" : app.getAppState() == YarnApplicationState.FINISHED .getTrackingUrl()),
app.getTrackingUrl() == null
|| app.getTrackingUrl().equals(UNAVAILABLE) ? "Unassigned" : app
.getAppState() == YarnApplicationState.FINISHED
|| app.getAppState() == YarnApplicationState.FAILED || app.getAppState() == YarnApplicationState.FAILED
|| app.getAppState() == YarnApplicationState.KILLED ? "History" || app.getAppState() == YarnApplicationState.KILLED ? "History"
: "ApplicationMaster") : "ApplicationMaster")
@ -210,6 +214,13 @@ public class AppBlock extends HtmlBlock {
html._(InfoBlock.class); html._(InfoBlock.class);
generateApplicationTable(html, callerUGI, attempts);
}
protected void generateApplicationTable(Block html,
UserGroupInformation callerUGI,
Collection<ApplicationAttemptReport> attempts) {
// Application Attempt Table // Application Attempt Table
TBODY<TABLE<Hamlet>> tbody = TBODY<TABLE<Hamlet>> tbody =
html.table("#attempts").thead().tr().th(".id", "Attempt ID") html.table("#attempts").thead().tr().th(".id", "Attempt ID")
@ -219,7 +230,7 @@ public class AppBlock extends HtmlBlock {
StringBuilder attemptsTableData = new StringBuilder("[\n"); StringBuilder attemptsTableData = new StringBuilder("[\n");
for (final ApplicationAttemptReport appAttemptReport : attempts) { for (final ApplicationAttemptReport appAttemptReport : attempts) {
AppAttemptInfo appAttempt = new AppAttemptInfo(appAttemptReport); AppAttemptInfo appAttempt = new AppAttemptInfo(appAttemptReport);
ContainerReport containerReport = null; ContainerReport containerReport;
try { try {
// AM container is always the first container of the attempt // AM container is always the first container of the attempt
final GetContainerReportRequest request = final GetContainerReportRequest request =
@ -230,7 +241,7 @@ public class AppBlock extends HtmlBlock {
appBaseProt.getContainerReport(request).getContainerReport(); appBaseProt.getContainerReport(request).getContainerReport();
} else { } else {
containerReport = callerUGI.doAs( containerReport = callerUGI.doAs(
new PrivilegedExceptionAction<ContainerReport> () { new PrivilegedExceptionAction<ContainerReport>() {
@Override @Override
public ContainerReport run() throws Exception { public ContainerReport run() throws Exception {
ContainerReport report = null; ContainerReport report = null;

View File

@ -23,6 +23,7 @@ import static org.apache.hadoop.yarn.webapp.YarnWebParams.APP_STATE;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR; import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR_VALUE; import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR_VALUE;
import java.io.IOException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.Collection; import java.util.Collection;
import java.util.EnumSet; import java.util.EnumSet;
@ -35,6 +36,7 @@ import org.apache.hadoop.yarn.api.ApplicationBaseProtocol;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest;
import org.apache.hadoop.yarn.api.records.ApplicationReport; import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.YarnApplicationState; import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.server.webapp.dao.AppInfo; import org.apache.hadoop.yarn.server.webapp.dao.AppInfo;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; 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.TABLE;
@ -47,26 +49,19 @@ public class AppsBlock extends HtmlBlock {
private static final Log LOG = LogFactory.getLog(AppsBlock.class); private static final Log LOG = LogFactory.getLog(AppsBlock.class);
protected ApplicationBaseProtocol appBaseProt; protected ApplicationBaseProtocol appBaseProt;
protected EnumSet<YarnApplicationState> reqAppStates;
protected UserGroupInformation callerUGI;
protected Collection<ApplicationReport> appReports;
@Inject @Inject
AppsBlock(ApplicationBaseProtocol appBaseProt, ViewContext ctx) { protected AppsBlock(ApplicationBaseProtocol appBaseProt, ViewContext ctx) {
super(ctx); super(ctx);
this.appBaseProt = appBaseProt; this.appBaseProt = appBaseProt;
} }
@Override protected void fetchData() throws YarnException, IOException,
public void render(Block html) { InterruptedException {
setTitle("Applications"); reqAppStates = EnumSet.noneOf(YarnApplicationState.class);
TBODY<TABLE<Hamlet>> tbody =
html.table("#apps").thead().tr().th(".id", "ID").th(".user", "User")
.th(".name", "Name").th(".type", "Application Type")
.th(".queue", "Queue").th(".starttime", "StartTime")
.th(".finishtime", "FinishTime").th(".state", "State")
.th(".finalstatus", "FinalStatus").th(".progress", "Progress")
.th(".ui", "Tracking UI")._()._().tbody();
EnumSet<YarnApplicationState> reqAppStates =
EnumSet.noneOf(YarnApplicationState.class);
String reqStateString = $(APP_STATE); String reqStateString = $(APP_STATE);
if (reqStateString != null && !reqStateString.isEmpty()) { if (reqStateString != null && !reqStateString.isEmpty()) {
String[] appStateStrings = reqStateString.split(","); String[] appStateStrings = reqStateString.split(",");
@ -75,28 +70,49 @@ public class AppsBlock extends HtmlBlock {
} }
} }
UserGroupInformation callerUGI = getCallerUGI(); callerUGI = getCallerUGI();
Collection<ApplicationReport> appReports = null;
try {
final GetApplicationsRequest request = final GetApplicationsRequest request =
GetApplicationsRequest.newInstance(reqAppStates); GetApplicationsRequest.newInstance(reqAppStates);
if (callerUGI == null) { if (callerUGI == null) {
appReports = appBaseProt.getApplications(request).getApplicationList(); appReports = appBaseProt.getApplications(request).getApplicationList();
} else { } else {
appReports = callerUGI.doAs( appReports =
new PrivilegedExceptionAction<Collection<ApplicationReport>> () { callerUGI
.doAs(new PrivilegedExceptionAction<Collection<ApplicationReport>>() {
@Override @Override
public Collection<ApplicationReport> run() throws Exception { public Collection<ApplicationReport> run() throws Exception {
return appBaseProt.getApplications(request).getApplicationList(); return appBaseProt.getApplications(request)
.getApplicationList();
} }
}); });
} }
} catch (Exception e) { }
@Override
public void render(Block html) {
setTitle("Applications");
try {
fetchData();
}
catch( Exception e) {
String message = "Failed to read the applications."; String message = "Failed to read the applications.";
LOG.error(message, e); LOG.error(message, e);
html.p()._(message)._(); html.p()._(message)._();
return; return;
} }
renderData(html);
}
protected void renderData(Block html) {
TBODY<TABLE<Hamlet>> tbody =
html.table("#apps").thead().tr().th(".id", "ID").th(".user", "User")
.th(".name", "Name").th(".type", "Application Type")
.th(".queue", "Queue").th(".starttime", "StartTime")
.th(".finishtime", "FinishTime").th(".state", "State")
.th(".finalstatus", "FinalStatus").th(".progress", "Progress")
.th(".ui", "Tracking UI")._()._().tbody();
StringBuilder appsTableData = new StringBuilder("[\n"); StringBuilder appsTableData = new StringBuilder("[\n");
for (ApplicationReport appReport : appReports) { for (ApplicationReport appReport : appReports) {
// TODO: remove the following condition. It is still here because // TODO: remove the following condition. It is still here because
@ -144,11 +160,12 @@ public class AppsBlock extends HtmlBlock {
.append("'> </div> </div>").append("\",\"<a "); .append("'> </div> </div>").append("\",\"<a ");
String trackingURL = String trackingURL =
app.getTrackingUrl() == null || app.getTrackingUrl() == UNAVAILABLE app.getTrackingUrl() == null
? null : app.getTrackingUrl(); || app.getTrackingUrl().equals(UNAVAILABLE) ? null : app
.getTrackingUrl();
String trackingUI = String trackingUI =
app.getTrackingUrl() == null || app.getTrackingUrl() == UNAVAILABLE app.getTrackingUrl() == null || app.getTrackingUrl().equals(UNAVAILABLE)
? "Unassigned" ? "Unassigned"
: app.getAppState() == YarnApplicationState.FINISHED : app.getAppState() == YarnApplicationState.FINISHED
|| app.getAppState() == YarnApplicationState.FAILED || app.getAppState() == YarnApplicationState.FAILED

View File

@ -462,6 +462,10 @@ public class AppSchedulingInfo {
return this.blacklist; return this.blacklist;
} }
public synchronized Set<String> getBlackListCopy() {
return new HashSet<>(this.blacklist);
}
public synchronized void transferStateFromPreviousAppSchedulingInfo( public synchronized void transferStateFromPreviousAppSchedulingInfo(
AppSchedulingInfo appInfo) { AppSchedulingInfo appInfo) {
// this.priorities = appInfo.getPriorities(); // this.priorities = appInfo.getPriorities();

View File

@ -665,4 +665,8 @@ public class SchedulerApplicationAttempt {
} }
} }
} }
public Set<String> getBlacklistedNodes() {
return this.appSchedulingInfo.getBlackListCopy();
}
} }

View File

@ -27,6 +27,6 @@ import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
class AppsBlockWithMetrics extends HtmlBlock { class AppsBlockWithMetrics extends HtmlBlock {
@Override public void render(Block html) { @Override public void render(Block html) {
html._(MetricsOverviewTable.class); html._(MetricsOverviewTable.class);
html._(AppsBlock.class); html._(RMAppsBlock.class);
} }
} }

View File

@ -239,7 +239,7 @@ class CapacitySchedulerPage extends RmView {
ul._()._(). ul._()._().
script().$type("text/javascript"). script().$type("text/javascript").
_("$('#cs').hide();")._()._(). _("$('#cs').hide();")._()._().
_(AppsBlock.class); _(RMAppsBlock.class);
} }
} }

View File

@ -23,8 +23,12 @@ 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._ODD;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH; import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport;
import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ContainerReport;
import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceRequest; import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.api.records.YarnApplicationAttemptState; import org.apache.hadoop.yarn.api.records.YarnApplicationAttemptState;
@ -32,8 +36,11 @@ 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.RMApp;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; 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.rmapp.attempt.RMAppAttemptMetrics;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.AbstractYarnScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerApplicationAttempt;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo;
import org.apache.hadoop.yarn.server.webapp.AppAttemptBlock; import org.apache.hadoop.yarn.server.webapp.AppAttemptBlock;
import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
import org.apache.hadoop.yarn.util.resource.Resources; import org.apache.hadoop.yarn.util.resource.Resources;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; 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.DIV;
@ -43,6 +50,9 @@ import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
import org.apache.hadoop.yarn.webapp.view.InfoBlock; import org.apache.hadoop.yarn.webapp.view.InfoBlock;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.Collection;
import java.util.Set;
public class RMAppAttemptBlock extends AppAttemptBlock{ public class RMAppAttemptBlock extends AppAttemptBlock{
private final ResourceManager rm; private final ResourceManager rm;
@ -174,4 +184,61 @@ public class RMAppAttemptBlock extends AppAttemptBlock{
} }
return attempt; return attempt;
} }
protected void generateOverview(ApplicationAttemptReport appAttemptReport,
Collection<ContainerReport> containers, AppAttemptInfo appAttempt,
String node) {
String blacklistedNodes = "-";
Set<String> nodes =
getBlacklistedNodes(rm, getRMAppAttempt().getAppAttemptId());
if (nodes != null) {
if (!nodes.isEmpty()) {
blacklistedNodes = StringUtils.join(nodes, ", ");
}
}
info("Application Attempt Overview")
._(
"Application Attempt State:",
appAttempt.getAppAttemptState() == null ? UNAVAILABLE : appAttempt
.getAppAttemptState())
._(
"AM Container:",
appAttempt.getAmContainerId() == null || containers == null
|| !hasAMContainer(appAttemptReport.getAMContainerId(), containers)
? null : root_url("container", appAttempt.getAmContainerId()),
String.valueOf(appAttempt.getAmContainerId()))
._("Node:", node)
._(
"Tracking URL:",
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl().equals(UNAVAILABLE) ? null
: root_url(appAttempt.getTrackingUrl()),
appAttempt.getTrackingUrl() == null
|| appAttempt.getTrackingUrl().equals(UNAVAILABLE)
? "Unassigned"
: appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FINISHED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FAILED
|| appAttempt.getAppAttemptState() == YarnApplicationAttemptState.KILLED
? "History" : "ApplicationMaster")
._(
"Diagnostics Info:",
appAttempt.getDiagnosticsInfo() == null ? "" : appAttempt
.getDiagnosticsInfo())._("Blacklisted Nodes:", blacklistedNodes);
}
public static Set<String> getBlacklistedNodes(ResourceManager rm,
ApplicationAttemptId appid) {
if (rm.getResourceScheduler() instanceof AbstractYarnScheduler) {
AbstractYarnScheduler ayScheduler =
(AbstractYarnScheduler) rm.getResourceScheduler();
SchedulerApplicationAttempt attempt =
ayScheduler.getApplicationAttempt(appid);
if (attempt != null) {
return attempt.getBlacklistedNodes();
}
}
return null;
}
} }

View File

@ -20,13 +20,25 @@ package org.apache.hadoop.yarn.server.resourcemanager.webapp;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.yarn.api.protocolrecords.GetContainerReportRequest;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport;
import org.apache.hadoop.yarn.api.records.ContainerId;
import org.apache.hadoop.yarn.api.records.ContainerReport;
import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.exceptions.ContainerNotFoundException;
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; 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.RMApp;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppMetrics; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppMetrics;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics;
import org.apache.hadoop.yarn.server.webapp.AppBlock; import org.apache.hadoop.yarn.server.webapp.AppBlock;
import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
import org.apache.hadoop.yarn.server.webapp.dao.ContainerInfo;
import org.apache.hadoop.yarn.util.ConverterUtils;
import org.apache.hadoop.yarn.util.resource.Resources; import org.apache.hadoop.yarn.util.resource.Resources;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; 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.DIV;
@ -34,10 +46,16 @@ import org.apache.hadoop.yarn.webapp.view.InfoBlock;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.Set;
public class RMAppBlock extends AppBlock{ public class RMAppBlock extends AppBlock{
private static final Log LOG = LogFactory.getLog(RMAppBlock.class);
private final ResourceManager rm; private final ResourceManager rm;
@Inject @Inject
RMAppBlock(ViewContext ctx, Configuration conf, ResourceManager rm) { RMAppBlock(ViewContext ctx, Configuration conf, ResourceManager rm) {
super(rm.getClientRMService(), ctx, conf); super(rm.getClientRMService(), ctx, conf);
@ -91,4 +109,96 @@ public class RMAppBlock extends AppBlock{
appMetrics == null ? "N/A" : appMetrics.getVcoreSeconds())); appMetrics == null ? "N/A" : appMetrics.getVcoreSeconds()));
pdiv._(); pdiv._();
} }
@Override
protected void generateApplicationTable(Block html,
UserGroupInformation callerUGI,
Collection<ApplicationAttemptReport> attempts) {
// Application Attempt Table
Hamlet.TBODY<Hamlet.TABLE<Hamlet>> tbody =
html.table("#attempts").thead().tr().th(".id", "Attempt ID")
.th(".started", "Started").th(".node", "Node").th(".logs", "Logs")
.th(".blacklistednodes", "Blacklisted Nodes")._()._().tbody();
StringBuilder attemptsTableData = new StringBuilder("[\n");
for (final ApplicationAttemptReport appAttemptReport : attempts) {
AppAttemptInfo appAttempt = new AppAttemptInfo(appAttemptReport);
ContainerReport containerReport = null;
try {
// AM container is always the first container of the attempt
final GetContainerReportRequest request =
GetContainerReportRequest.newInstance(ContainerId.newContainerId(
appAttemptReport.getApplicationAttemptId(), 1));
if (callerUGI == null) {
containerReport =
appBaseProt.getContainerReport(request).getContainerReport();
} else {
containerReport = callerUGI.doAs(
new PrivilegedExceptionAction<ContainerReport>() {
@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 =
"Failed to read the AM container of the application attempt "
+ appAttemptReport.getApplicationAttemptId() + ".";
LOG.error(message, e);
html.p()._(message)._();
return;
}
long startTime = 0L;
String logsLink = null;
String nodeLink = null;
if (containerReport != null) {
ContainerInfo container = new ContainerInfo(containerReport);
startTime = container.getStartedTime();
logsLink = containerReport.getLogUrl();
nodeLink = containerReport.getNodeHttpAddress();
}
String blacklistedNodesCount = "N/A";
Set<String> nodes = RMAppAttemptBlock.getBlacklistedNodes(rm,
ConverterUtils.toApplicationAttemptId(appAttempt.getAppAttemptId()));
if(nodes != null) {
blacklistedNodesCount = String.valueOf(nodes.size());
}
// AppAttemptID numerical value parsed by parseHadoopID in
// yarn.dt.plugins.js
attemptsTableData
.append("[\"<a href='")
.append(url("appattempt", appAttempt.getAppAttemptId()))
.append("'>")
.append(appAttempt.getAppAttemptId())
.append("</a>\",\"")
.append(startTime)
.append("\",\"<a ")
.append(nodeLink == null ? "#" : "href='" + nodeLink)
.append("'>")
.append(nodeLink == null ? "N/A" : StringEscapeUtils
.escapeJavaScript(StringEscapeUtils.escapeHtml(nodeLink)))
.append("</a>\",\"<a ")
.append(logsLink == null ? "#" : "href='" + logsLink).append("'>")
.append(logsLink == null ? "N/A" : "Logs").append("</a>\",").append(
"\"").append(blacklistedNodesCount).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._()._();
}
} }

View File

@ -0,0 +1,146 @@
/**
* 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.resourcemanager.webapp;
import static org.apache.hadoop.yarn.util.StringHelper.join;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR;
import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR_VALUE;
import java.util.Set;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.hadoop.yarn.api.ApplicationBaseProtocol;
import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
import org.apache.hadoop.yarn.server.webapp.AppsBlock;
import org.apache.hadoop.yarn.server.webapp.dao.AppInfo;
import org.apache.hadoop.yarn.util.ConverterUtils;
import org.apache.hadoop.yarn.webapp.View;
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 com.google.inject.Inject;
public class RMAppsBlock extends AppsBlock {
private ResourceManager rm;
@Inject
RMAppsBlock(ResourceManager rm, ApplicationBaseProtocol appBaseProt,
View.ViewContext ctx) {
super(appBaseProt, ctx);
this.rm = rm;
}
@Override
protected void renderData(Block html) {
TBODY<TABLE<Hamlet>> tbody =
html.table("#apps").thead().tr().th(".id", "ID").th(".user", "User")
.th(".name", "Name").th(".type", "Application Type")
.th(".queue", "Queue").th(".starttime", "StartTime")
.th(".finishtime", "FinishTime").th(".state", "State")
.th(".finalstatus", "FinalStatus").th(".progress", "Progress")
.th(".ui", "Tracking UI").th(".blacklisted", "Blacklisted Nodes")._()
._().tbody();
StringBuilder appsTableData = new StringBuilder("[\n");
for (ApplicationReport appReport : appReports) {
// TODO: remove the following condition. It is still here because
// the history side implementation of ApplicationBaseProtocol
// hasn't filtering capability (YARN-1819).
if (!reqAppStates.isEmpty()
&& !reqAppStates.contains(appReport.getYarnApplicationState())) {
continue;
}
AppInfo app = new AppInfo(appReport);
String blacklistedNodesCount = "N/A";
Set<String> nodes =
RMAppAttemptBlock
.getBlacklistedNodes(rm, ConverterUtils.toApplicationAttemptId(app
.getCurrentAppAttemptId()));
if (nodes != null) {
blacklistedNodesCount = String.valueOf(nodes.size());
}
String percent = String.format("%.1f", app.getProgress());
// AppID numerical value parsed by parseHadoopID in yarn.dt.plugins.js
appsTableData
.append("[\"<a href='")
.append(url("app", app.getAppId()))
.append("'>")
.append(app.getAppId())
.append("</a>\",\"")
.append(
StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app
.getUser())))
.append("\",\"")
.append(
StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app
.getName())))
.append("\",\"")
.append(
StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app
.getType())))
.append("\",\"")
.append(
StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app
.getQueue()))).append("\",\"").append(app.getStartedTime())
.append("\",\"").append(app.getFinishedTime())
.append("\",\"")
.append(app.getAppState() == null ? UNAVAILABLE : app.getAppState())
.append("\",\"")
.append(app.getFinalAppStatus())
.append("\",\"")
// Progress bar
.append("<br title='").append(percent).append("'> <div class='")
.append(C_PROGRESSBAR).append("' title='").append(join(percent, '%'))
.append("'> ").append("<div class='").append(C_PROGRESSBAR_VALUE)
.append("' style='").append(join("width:", percent, '%'))
.append("'> </div> </div>").append("\",\"<a ");
String trackingURL =
app.getTrackingUrl() == null
|| app.getTrackingUrl().equals(UNAVAILABLE) ? null : app
.getTrackingUrl();
String trackingUI =
app.getTrackingUrl() == null
|| app.getTrackingUrl().equals(UNAVAILABLE) ? "Unassigned" : app
.getAppState() == YarnApplicationState.FINISHED
|| app.getAppState() == YarnApplicationState.FAILED
|| app.getAppState() == YarnApplicationState.KILLED ? "History"
: "ApplicationMaster";
appsTableData.append(trackingURL == null ? "#" : "href='" + trackingURL)
.append("'>").append(trackingUI).append("</a>\",").append("\"")
.append(blacklistedNodesCount).append("\"],\n");
}
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._()._();
}
}

View File

@ -647,7 +647,8 @@ public class RMWebServices {
AppAttemptsInfo appAttemptsInfo = new AppAttemptsInfo(); AppAttemptsInfo appAttemptsInfo = new AppAttemptsInfo();
for (RMAppAttempt attempt : app.getAppAttempts().values()) { for (RMAppAttempt attempt : app.getAppAttempts().values()) {
AppAttemptInfo attemptInfo = new AppAttemptInfo(attempt, app.getUser()); AppAttemptInfo attemptInfo =
new AppAttemptInfo(rm, attempt, app.getUser());
appAttemptsInfo.add(attemptInfo); appAttemptsInfo.add(attemptInfo);
} }

View File

@ -21,8 +21,13 @@ import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.yarn.api.records.Container; import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.AbstractYarnScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerApplicationAttempt;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMAppAttemptBlock;
import org.apache.hadoop.yarn.util.ConverterUtils; import org.apache.hadoop.yarn.util.ConverterUtils;
import org.apache.hadoop.yarn.webapp.util.WebAppUtils; import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
@ -36,16 +41,18 @@ public class AppAttemptInfo {
protected String nodeHttpAddress; protected String nodeHttpAddress;
protected String nodeId; protected String nodeId;
protected String logsLink; protected String logsLink;
protected String blacklistedNodes;
public AppAttemptInfo() { public AppAttemptInfo() {
} }
public AppAttemptInfo(RMAppAttempt attempt, String user) { public AppAttemptInfo(ResourceManager rm, RMAppAttempt attempt, String user) {
this.startTime = 0; this.startTime = 0;
this.containerId = ""; this.containerId = "";
this.nodeHttpAddress = ""; this.nodeHttpAddress = "";
this.nodeId = ""; this.nodeId = "";
this.logsLink = ""; this.logsLink = "";
this.blacklistedNodes = "";
if (attempt != null) { if (attempt != null) {
this.id = attempt.getAppAttemptId().getAttemptId(); this.id = attempt.getAppAttemptId().getAttemptId();
this.startTime = attempt.getStartTime(); this.startTime = attempt.getStartTime();
@ -57,6 +64,16 @@ public class AppAttemptInfo {
this.logsLink = this.logsLink =
WebAppUtils.getRunningLogURL("//" + masterContainer.getNodeHttpAddress(), WebAppUtils.getRunningLogURL("//" + masterContainer.getNodeHttpAddress(),
ConverterUtils.toString(masterContainer.getId()), user); ConverterUtils.toString(masterContainer.getId()), user);
if (rm.getResourceScheduler() instanceof AbstractYarnScheduler) {
AbstractYarnScheduler ayScheduler =
(AbstractYarnScheduler) rm.getResourceScheduler();
SchedulerApplicationAttempt sattempt =
ayScheduler.getApplicationAttempt(attempt.getAppAttemptId());
if (sattempt != null) {
blacklistedNodes =
StringUtils.join(sattempt.getBlacklistedNodes(), ", ");
}
}
} }
} }
} }

View File

@ -1598,7 +1598,7 @@ public class TestRMWebServicesApps extends JerseyTestBase {
String user) String user)
throws JSONException, Exception { throws JSONException, Exception {
assertEquals("incorrect number of elements", 6, info.length()); assertEquals("incorrect number of elements", 7, info.length());
verifyAppAttemptInfoGeneric(appAttempt, info.getInt("id"), verifyAppAttemptInfoGeneric(appAttempt, info.getInt("id"),
info.getLong("startTime"), info.getString("containerId"), info.getLong("startTime"), info.getString("containerId"),