merge -r 1346046:1346047 from trunk. FIXES: MAPREDUCE-3350
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1346048 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c59349ede3
commit
3dc10a25d9
|
@ -443,6 +443,9 @@ Release 0.23.3 - UNRELEASED
|
||||||
MAPREDUCE-4302. NM goes down if error encountered during log aggregation
|
MAPREDUCE-4302. NM goes down if error encountered during log aggregation
|
||||||
(Daryn Sharp via bobby)
|
(Daryn Sharp via bobby)
|
||||||
|
|
||||||
|
MAPREDUCE-3350. Per-app RM page should have the list of application-attempts
|
||||||
|
like on the app JHS page (Jonathon Eagles via tgraves)
|
||||||
|
|
||||||
Release 0.23.2 - UNRELEASED
|
Release 0.23.2 - UNRELEASED
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -135,10 +135,11 @@ public class HsJobBlock extends HtmlBlock {
|
||||||
th(_TH, "Node").
|
th(_TH, "Node").
|
||||||
th(_TH, "Logs").
|
th(_TH, "Logs").
|
||||||
_();
|
_();
|
||||||
|
boolean odd = false;
|
||||||
for (AMInfo amInfo : amInfos) {
|
for (AMInfo amInfo : amInfos) {
|
||||||
AMAttemptInfo attempt = new AMAttemptInfo(amInfo,
|
AMAttemptInfo attempt = new AMAttemptInfo(amInfo,
|
||||||
job.getId(), job.getUserName(), "", "");
|
job.getId(), job.getUserName(), "", "");
|
||||||
table.tr().
|
table.tr((odd = !odd) ? _ODD : _EVEN).
|
||||||
td(String.valueOf(attempt.getAttemptId())).
|
td(String.valueOf(attempt.getAttemptId())).
|
||||||
td(new Date(attempt.getStartTime()).toString()).
|
td(new Date(attempt.getStartTime()).toString()).
|
||||||
td().a(".nodelink", url("http://", attempt.getNodeHttpAddress()),
|
td().a(".nodelink", url("http://", attempt.getNodeHttpAddress()),
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.hadoop.yarn.server.resourcemanager.rmapp;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.FinishApplicationMasterRequest;
|
import org.apache.hadoop.yarn.api.protocolrecords.FinishApplicationMasterRequest;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
|
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
|
||||||
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
|
@ -93,6 +95,13 @@ public interface RMApp extends EventHandler<RMAppEvent> {
|
||||||
*/
|
*/
|
||||||
RMAppAttempt getCurrentAppAttempt();
|
RMAppAttempt getCurrentAppAttempt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link RMApp} can have multiple application attempts {@link RMAppAttempt}.
|
||||||
|
* This method returns the all {@link RMAppAttempt}s for the RMApp.
|
||||||
|
* @return all {@link RMAppAttempt}s for the RMApp.
|
||||||
|
*/
|
||||||
|
Map<ApplicationAttemptId, RMAppAttempt> getAppAttempts();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To get the status of an application in the RM, this method can be used.
|
* To get the status of an application in the RM, this method can be used.
|
||||||
* If full access is not allowed then the following fields in the report
|
* If full access is not allowed then the following fields in the report
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager.rmapp;
|
package org.apache.hadoop.yarn.server.resourcemanager.rmapp;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -311,6 +312,17 @@ public class RMAppImpl implements RMApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<ApplicationAttemptId, RMAppAttempt> getAppAttempts() {
|
||||||
|
this.readLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Collections.unmodifiableMap(this.attempts);
|
||||||
|
} finally {
|
||||||
|
this.readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApplicationStore getApplicationStore() {
|
public ApplicationStore getApplicationStore() {
|
||||||
return this.appStore;
|
return this.appStore;
|
||||||
|
|
|
@ -145,9 +145,15 @@ public interface RMAppAttempt extends EventHandler<RMAppAttemptEvent> {
|
||||||
*/
|
*/
|
||||||
ApplicationSubmissionContext getSubmissionContext();
|
ApplicationSubmissionContext getSubmissionContext();
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Get application container and resource usage information.
|
* Get application container and resource usage information.
|
||||||
* @return an ApplicationResourceUsageReport object.
|
* @return an ApplicationResourceUsageReport object.
|
||||||
*/
|
*/
|
||||||
ApplicationResourceUsageReport getApplicationResourceUsageReport();
|
ApplicationResourceUsageReport getApplicationResourceUsageReport();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the start time of the application.
|
||||||
|
* @return the start time of the application.
|
||||||
|
*/
|
||||||
|
long getStartTime();
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,7 @@ public class RMAppAttemptImpl implements RMAppAttempt {
|
||||||
private int rpcPort;
|
private int rpcPort;
|
||||||
private String origTrackingUrl = "N/A";
|
private String origTrackingUrl = "N/A";
|
||||||
private String proxiedTrackingUrl = "N/A";
|
private String proxiedTrackingUrl = "N/A";
|
||||||
|
private long startTime = 0;
|
||||||
|
|
||||||
// Set to null initially. Will eventually get set
|
// Set to null initially. Will eventually get set
|
||||||
// if an RMAppAttemptUnregistrationEvent occurs
|
// if an RMAppAttemptUnregistrationEvent occurs
|
||||||
|
@ -543,6 +544,8 @@ public class RMAppAttemptImpl implements RMAppAttempt {
|
||||||
public void transition(RMAppAttemptImpl appAttempt,
|
public void transition(RMAppAttemptImpl appAttempt,
|
||||||
RMAppAttemptEvent event) {
|
RMAppAttemptEvent event) {
|
||||||
|
|
||||||
|
appAttempt.startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
// Register with the ApplicationMasterService
|
// Register with the ApplicationMasterService
|
||||||
appAttempt.masterService
|
appAttempt.masterService
|
||||||
.registerAppAttempt(appAttempt.applicationAttemptId);
|
.registerAppAttempt(appAttempt.applicationAttemptId);
|
||||||
|
@ -912,4 +915,14 @@ public class RMAppAttemptImpl implements RMAppAttempt {
|
||||||
return RMAppAttemptState.RUNNING;
|
return RMAppAttemptState.RUNNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getStartTime() {
|
||||||
|
this.readLock.lock();
|
||||||
|
try {
|
||||||
|
return this.startTime;
|
||||||
|
} finally {
|
||||||
|
this.readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,13 @@ package org.apache.hadoop.yarn.server.resourcemanager.webapp;
|
||||||
|
|
||||||
import static org.apache.hadoop.yarn.util.StringHelper.join;
|
import static org.apache.hadoop.yarn.util.StringHelper.join;
|
||||||
import static org.apache.hadoop.yarn.webapp.YarnWebParams.APPLICATION_ID;
|
import static org.apache.hadoop.yarn.webapp.YarnWebParams.APPLICATION_ID;
|
||||||
|
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.util.Collection;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
@ -29,14 +36,18 @@ import org.apache.hadoop.yarn.api.records.ApplicationAccessType;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||||
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.webapp.dao.AppAttemptInfo;
|
||||||
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.resourcemanager.ResourceManager;
|
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
|
||||||
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
||||||
import org.apache.hadoop.yarn.util.Apps;
|
import org.apache.hadoop.yarn.util.Apps;
|
||||||
import org.apache.hadoop.yarn.util.Times;
|
import org.apache.hadoop.yarn.util.Times;
|
||||||
|
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.HtmlBlock;
|
||||||
import org.apache.hadoop.yarn.webapp.view.InfoBlock;
|
import org.apache.hadoop.yarn.webapp.view.InfoBlock;
|
||||||
import org.apache.hadoop.yarn.webapp.ResponseInfo;
|
|
||||||
|
|
||||||
public class AppBlock extends HtmlBlock {
|
public class AppBlock extends HtmlBlock {
|
||||||
|
|
||||||
|
@ -88,7 +99,7 @@ public class AppBlock extends HtmlBlock {
|
||||||
|
|
||||||
setTitle(join("Application ", aid));
|
setTitle(join("Application ", aid));
|
||||||
|
|
||||||
ResponseInfo info = info("Application Overview").
|
info("Application Overview").
|
||||||
_("User:", app.getUser()).
|
_("User:", app.getUser()).
|
||||||
_("Name:", app.getName()).
|
_("Name:", app.getName()).
|
||||||
_("State:", app.getState()).
|
_("State:", app.getState()).
|
||||||
|
@ -99,12 +110,40 @@ public class AppBlock extends HtmlBlock {
|
||||||
_("Tracking URL:", !app.isTrackingUrlReady() ?
|
_("Tracking URL:", !app.isTrackingUrlReady() ?
|
||||||
"#" : app.getTrackingUrlPretty(), app.getTrackingUI()).
|
"#" : app.getTrackingUrlPretty(), app.getTrackingUI()).
|
||||||
_("Diagnostics:", app.getNote());
|
_("Diagnostics:", app.getNote());
|
||||||
if (app.amContainerLogsExist()) {
|
|
||||||
info._("AM container logs:", app.getAMContainerLogs(), app.getAMContainerLogs());
|
Collection<RMAppAttempt> attempts = rmApp.getAppAttempts().values();
|
||||||
} else {
|
String amString =
|
||||||
info._("AM container logs:", "");
|
attempts.size() == 1 ? "ApplicationMaster" : "ApplicationMasters";
|
||||||
|
|
||||||
|
DIV<Hamlet> div = html.
|
||||||
|
_(InfoBlock.class).
|
||||||
|
div(_INFO_WRAP);
|
||||||
|
// MRAppMasters Table
|
||||||
|
TABLE<DIV<Hamlet>> table = div.table("#app");
|
||||||
|
table.
|
||||||
|
tr().
|
||||||
|
th(amString).
|
||||||
|
_().
|
||||||
|
tr().
|
||||||
|
th(_TH, "Attempt Number").
|
||||||
|
th(_TH, "Start Time").
|
||||||
|
th(_TH, "Node").
|
||||||
|
th(_TH, "Logs").
|
||||||
|
_();
|
||||||
|
|
||||||
|
boolean odd = false;
|
||||||
|
for (RMAppAttempt attempt : attempts) {
|
||||||
|
AppAttemptInfo attemptInfo = new AppAttemptInfo(attempt);
|
||||||
|
table.tr((odd = !odd) ? _ODD : _EVEN).
|
||||||
|
td(String.valueOf(attemptInfo.getAttemptId())).
|
||||||
|
td(Times.format(attemptInfo.getStartTime())).
|
||||||
|
td().a(".nodelink", url("http://", attemptInfo.getNodeHttpAddress()),
|
||||||
|
attemptInfo.getNodeHttpAddress())._().
|
||||||
|
td().a(".logslink", url(attemptInfo.getLogsLink()), "logs")._().
|
||||||
|
_();
|
||||||
}
|
}
|
||||||
|
|
||||||
html._(InfoBlock.class);
|
table._();
|
||||||
|
div._();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import javax.ws.rs.ext.Provider;
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
|
|
||||||
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.resourcemanager.webapp.dao.AppAttemptInfo;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptsInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerQueueInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerQueueInfo;
|
||||||
|
@ -53,7 +55,8 @@ public class JAXBContextResolver implements ContextResolver<JAXBContext> {
|
||||||
private final Set<Class> types;
|
private final Set<Class> types;
|
||||||
|
|
||||||
// you have to specify all the dao classes here
|
// you have to specify all the dao classes here
|
||||||
private final Class[] cTypes = { AppInfo.class, ClusterInfo.class,
|
private final Class[] cTypes = { AppInfo.class, AppAttemptInfo.class,
|
||||||
|
AppAttemptsInfo.class, ClusterInfo.class,
|
||||||
CapacitySchedulerQueueInfo.class, FifoSchedulerInfo.class,
|
CapacitySchedulerQueueInfo.class, FifoSchedulerInfo.class,
|
||||||
SchedulerTypeInfo.class, NodeInfo.class, UserMetricsInfo.class,
|
SchedulerTypeInfo.class, NodeInfo.class, UserMetricsInfo.class,
|
||||||
CapacitySchedulerInfo.class, ClusterMetricsInfo.class,
|
CapacitySchedulerInfo.class, ClusterMetricsInfo.class,
|
||||||
|
|
|
@ -45,11 +45,14 @@ import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider;
|
||||||
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.RMAppState;
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode;
|
import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptInfo;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptsInfo;
|
||||||
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.resourcemanager.webapp.dao.AppsInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo;
|
||||||
|
@ -385,4 +388,31 @@ public class RMWebServices {
|
||||||
return new AppInfo(app, hasAccess(app, hsr));
|
return new AppInfo(app, hasAccess(app, hsr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/apps/{appid}/appattempts")
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||||
|
public AppAttemptsInfo getAppAttempts(@PathParam("appid") String appId) {
|
||||||
|
|
||||||
|
init();
|
||||||
|
if (appId == null || appId.isEmpty()) {
|
||||||
|
throw new NotFoundException("appId, " + appId + ", is empty or null");
|
||||||
|
}
|
||||||
|
ApplicationId id;
|
||||||
|
id = ConverterUtils.toApplicationId(recordFactory, appId);
|
||||||
|
if (id == null) {
|
||||||
|
throw new NotFoundException("appId is null");
|
||||||
|
}
|
||||||
|
RMApp app = rm.getRMContext().getRMApps().get(id);
|
||||||
|
if (app == null) {
|
||||||
|
throw new NotFoundException("app with id: " + appId + " not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppAttemptsInfo appAttemptsInfo = new AppAttemptsInfo();
|
||||||
|
for (RMAppAttempt attempt : app.getAppAttempts().values()) {
|
||||||
|
AppAttemptInfo attemptInfo = new AppAttemptInfo(attempt);
|
||||||
|
appAttemptsInfo.add(attemptInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return appAttemptsInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.server.resourcemanager.applicationsmanager;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.yarn.MockApps;
|
import org.apache.hadoop.yarn.MockApps;
|
||||||
|
@ -189,6 +190,10 @@ public abstract class MockAsm extends MockApps {
|
||||||
throw new UnsupportedOperationException("Not supported yet.");
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
public Map<ApplicationAttemptId, RMAppAttempt> getAppAttempts() {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
public ApplicationStore getApplicationStore() {
|
public ApplicationStore getApplicationStore() {
|
||||||
throw new UnsupportedOperationException("Not supported yet.");
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ package org.apache.hadoop.yarn.server.resourcemanager.rmapp;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
|
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
|
||||||
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
|
@ -112,6 +115,14 @@ public class MockRMApp implements RMApp {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<ApplicationAttemptId, RMAppAttempt> getAppAttempts() {
|
||||||
|
Map<ApplicationAttemptId, RMAppAttempt> attempts =
|
||||||
|
new LinkedHashMap<ApplicationAttemptId, RMAppAttempt>();
|
||||||
|
attempts.put(attempt.getAppAttemptId(), attempt);
|
||||||
|
return attempts;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RMAppAttempt getCurrentAppAttempt() {
|
public RMAppAttempt getCurrentAppAttempt() {
|
||||||
return attempt;
|
return attempt;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
@ -31,13 +32,18 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.MockAM;
|
import org.apache.hadoop.yarn.server.resourcemanager.MockAM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.MockNM;
|
import org.apache.hadoop.yarn.server.resourcemanager.MockNM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
|
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||||
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.RMAppEvent;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppEventType;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppFailedAttemptEvent;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState;
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
|
||||||
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
|
||||||
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
|
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
|
||||||
import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
|
import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
|
||||||
|
@ -73,7 +79,9 @@ public class TestRMWebServicesApps extends JerseyTest {
|
||||||
bind(JAXBContextResolver.class);
|
bind(JAXBContextResolver.class);
|
||||||
bind(RMWebServices.class);
|
bind(RMWebServices.class);
|
||||||
bind(GenericExceptionHandler.class);
|
bind(GenericExceptionHandler.class);
|
||||||
rm = new MockRM(new Configuration());
|
Configuration conf = new Configuration();
|
||||||
|
conf.setInt(YarnConfiguration.RM_AM_MAX_RETRIES, 2);
|
||||||
|
rm = new MockRM(conf);
|
||||||
bind(ResourceManager.class).toInstance(rm);
|
bind(ResourceManager.class).toInstance(rm);
|
||||||
bind(RMContext.class).toInstance(rm.getRMContext());
|
bind(RMContext.class).toInstance(rm.getRMContext());
|
||||||
bind(ApplicationACLsManager.class).toInstance(
|
bind(ApplicationACLsManager.class).toInstance(
|
||||||
|
@ -835,4 +843,234 @@ public class TestRMWebServicesApps extends JerseyTest {
|
||||||
amContainerLogs.endsWith("/" + app.getUser()));
|
amContainerLogs.endsWith("/" + app.getUser()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppAttempts() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
RMApp app1 = rm.submitApp(1024, "testwordcount", "user1");
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
testAppAttemptsHelper(app1.getApplicationId().toString(), app1,
|
||||||
|
MediaType.APPLICATION_JSON);
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleAppAttempts() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
RMApp app1 = rm.submitApp(1024, "testwordcount", "user1");
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
int maxRetries = rm.getConfig().getInt(YarnConfiguration.RM_AM_MAX_RETRIES,
|
||||||
|
YarnConfiguration.DEFAULT_RM_AM_MAX_RETRIES);
|
||||||
|
int retriesLeft = maxRetries;
|
||||||
|
while (--retriesLeft > 0) {
|
||||||
|
RMAppEvent event =
|
||||||
|
new RMAppFailedAttemptEvent(app1.getApplicationId(),
|
||||||
|
RMAppEventType.ATTEMPT_FAILED, "");
|
||||||
|
app1.handle(event);
|
||||||
|
rm.waitForState(app1.getApplicationId(), RMAppState.ACCEPTED);
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
}
|
||||||
|
assertEquals("incorrect number of attempts", maxRetries,
|
||||||
|
app1.getAppAttempts().values().size());
|
||||||
|
testAppAttemptsHelper(app1.getApplicationId().toString(), app1,
|
||||||
|
MediaType.APPLICATION_JSON);
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppAttemptsSlash() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
RMApp app1 = rm.submitApp(1024);
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
testAppAttemptsHelper(app1.getApplicationId().toString() + "/", app1,
|
||||||
|
MediaType.APPLICATION_JSON);
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppAttemtpsDefault() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
RMApp app1 = rm.submitApp(1024);
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
testAppAttemptsHelper(app1.getApplicationId().toString() + "/", app1, "");
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidAppAttempts() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
rm.submitApp(1024);
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
WebResource r = resource();
|
||||||
|
|
||||||
|
try {
|
||||||
|
r.path("ws").path("v1").path("cluster").path("apps")
|
||||||
|
.path("application_invalid_12").accept(MediaType.APPLICATION_JSON)
|
||||||
|
.get(JSONObject.class);
|
||||||
|
fail("should have thrown exception on invalid appid");
|
||||||
|
} catch (UniformInterfaceException ue) {
|
||||||
|
ClientResponse response = ue.getResponse();
|
||||||
|
|
||||||
|
assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus());
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
JSONObject msg = response.getEntity(JSONObject.class);
|
||||||
|
JSONObject exception = msg.getJSONObject("RemoteException");
|
||||||
|
assertEquals("incorrect number of elements", 3, exception.length());
|
||||||
|
String message = exception.getString("message");
|
||||||
|
String type = exception.getString("exception");
|
||||||
|
String classname = exception.getString("javaClassName");
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception message",
|
||||||
|
"For input string: \"invalid\"", message);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception type",
|
||||||
|
"NumberFormatException", type);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception classname",
|
||||||
|
"java.lang.NumberFormatException", classname);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonexistAppAttempts() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
rm.submitApp(1024, "testwordcount", "user1");
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
WebResource r = resource();
|
||||||
|
|
||||||
|
try {
|
||||||
|
r.path("ws").path("v1").path("cluster").path("apps")
|
||||||
|
.path("application_00000_0099").accept(MediaType.APPLICATION_JSON)
|
||||||
|
.get(JSONObject.class);
|
||||||
|
fail("should have thrown exception on invalid appid");
|
||||||
|
} catch (UniformInterfaceException ue) {
|
||||||
|
ClientResponse response = ue.getResponse();
|
||||||
|
|
||||||
|
assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
|
||||||
|
JSONObject msg = response.getEntity(JSONObject.class);
|
||||||
|
JSONObject exception = msg.getJSONObject("RemoteException");
|
||||||
|
assertEquals("incorrect number of elements", 3, exception.length());
|
||||||
|
String message = exception.getString("message");
|
||||||
|
String type = exception.getString("exception");
|
||||||
|
String classname = exception.getString("javaClassName");
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception message",
|
||||||
|
"java.lang.Exception: app with id: application_00000_0099 not found",
|
||||||
|
message);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception type",
|
||||||
|
"NotFoundException", type);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception classname",
|
||||||
|
"org.apache.hadoop.yarn.webapp.NotFoundException", classname);
|
||||||
|
} finally {
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAppAttemptsHelper(String path, RMApp app, String media)
|
||||||
|
throws JSONException, Exception {
|
||||||
|
WebResource r = resource();
|
||||||
|
ClientResponse response = r.path("ws").path("v1").path("cluster")
|
||||||
|
.path("apps").path(path).path("appattempts").accept(media)
|
||||||
|
.get(ClientResponse.class);
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
JSONObject json = response.getEntity(JSONObject.class);
|
||||||
|
assertEquals("incorrect number of elements", 1, json.length());
|
||||||
|
JSONObject jsonAppAttempts = json.getJSONObject("appAttempts");
|
||||||
|
assertEquals("incorrect number of elements", 1, jsonAppAttempts.length());
|
||||||
|
JSONArray jsonArray = jsonAppAttempts.getJSONArray("appAttempt");
|
||||||
|
|
||||||
|
Collection<RMAppAttempt> attempts = app.getAppAttempts().values();
|
||||||
|
assertEquals("incorrect number of elements", attempts.size(),
|
||||||
|
jsonArray.length());
|
||||||
|
|
||||||
|
// Verify these parallel arrays are the same
|
||||||
|
int i = 0;
|
||||||
|
for (RMAppAttempt attempt : attempts) {
|
||||||
|
verifyAppAttemptsInfo(jsonArray.getJSONObject(i), attempt);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppAttemptsXML() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
RMApp app1 = rm.submitApp(1024, "testwordcount", "user1");
|
||||||
|
amNodeManager.nodeHeartbeat(true);
|
||||||
|
WebResource r = resource();
|
||||||
|
ClientResponse response = r.path("ws").path("v1").path("cluster")
|
||||||
|
.path("apps").path(app1.getApplicationId().toString())
|
||||||
|
.path("appattempts").accept(MediaType.APPLICATION_XML)
|
||||||
|
.get(ClientResponse.class);
|
||||||
|
assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
|
||||||
|
String xml = response.getEntity(String.class);
|
||||||
|
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||||
|
InputSource is = new InputSource();
|
||||||
|
is.setCharacterStream(new StringReader(xml));
|
||||||
|
Document dom = db.parse(is);
|
||||||
|
NodeList nodes = dom.getElementsByTagName("appAttempts");
|
||||||
|
assertEquals("incorrect number of elements", 1, nodes.getLength());
|
||||||
|
NodeList attempt = dom.getElementsByTagName("appAttempt");
|
||||||
|
assertEquals("incorrect number of elements", 1, attempt.getLength());
|
||||||
|
verifyAppAttemptsXML(attempt, app1.getCurrentAppAttempt());
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void verifyAppAttemptsXML(NodeList nodes, RMAppAttempt appAttempt)
|
||||||
|
throws JSONException, Exception {
|
||||||
|
|
||||||
|
for (int i = 0; i < nodes.getLength(); i++) {
|
||||||
|
Element element = (Element) nodes.item(i);
|
||||||
|
|
||||||
|
verifyAppAttemptInfoGeneric(appAttempt,
|
||||||
|
WebServicesTestUtils.getXmlInt(element, "id"),
|
||||||
|
WebServicesTestUtils.getXmlLong(element, "startTime"),
|
||||||
|
WebServicesTestUtils.getXmlString(element, "containerId"),
|
||||||
|
WebServicesTestUtils.getXmlString(element, "nodeHttpAddress"),
|
||||||
|
WebServicesTestUtils.getXmlString(element, "nodeId"),
|
||||||
|
WebServicesTestUtils.getXmlString(element, "logsLink"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void verifyAppAttemptsInfo(JSONObject info, RMAppAttempt appAttempt)
|
||||||
|
throws JSONException, Exception {
|
||||||
|
|
||||||
|
assertEquals("incorrect number of elements", 6, info.length());
|
||||||
|
|
||||||
|
verifyAppAttemptInfoGeneric(appAttempt, info.getInt("id"),
|
||||||
|
info.getLong("startTime"), info.getString("containerId"),
|
||||||
|
info.getString("nodeHttpAddress"), info.getString("nodeId"),
|
||||||
|
info.getString("logsLink"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void verifyAppAttemptInfoGeneric(RMAppAttempt appAttempt, int id,
|
||||||
|
long startTime, String containerId, String nodeHttpAddress, String nodeId,
|
||||||
|
String logsLink)
|
||||||
|
throws JSONException, Exception {
|
||||||
|
|
||||||
|
assertEquals("id doesn't match", appAttempt.getAppAttemptId()
|
||||||
|
.getAttemptId(), id);
|
||||||
|
assertEquals("startedTime doesn't match", appAttempt.getStartTime(),
|
||||||
|
startTime);
|
||||||
|
WebServicesTestUtils.checkStringMatch("containerId", appAttempt
|
||||||
|
.getMasterContainer().getId().toString(), containerId);
|
||||||
|
WebServicesTestUtils.checkStringMatch("nodeHttpAddress", appAttempt
|
||||||
|
.getMasterContainer().getNodeHttpAddress(), nodeHttpAddress);
|
||||||
|
WebServicesTestUtils.checkStringMatch("nodeId", appAttempt
|
||||||
|
.getMasterContainer().getNodeId().toString(), nodeId);
|
||||||
|
assertTrue("logsLink doesn't match",
|
||||||
|
logsLink.startsWith("http://"));
|
||||||
|
assertTrue("logsLink doesn't contain user info",
|
||||||
|
logsLink.endsWith("/" + appAttempt.getSubmissionContext().getUser()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1236,6 +1236,130 @@ _01_000001</amContainerLogs>
|
||||||
</app>
|
</app>
|
||||||
+---+
|
+---+
|
||||||
|
|
||||||
|
* Cluster Application Attempts API
|
||||||
|
|
||||||
|
With the application attempts API, you can obtain a collection of resources that represent an application attempt. When you run a GET operation on this resource, you obtain a collection of App Attempt Objects.
|
||||||
|
|
||||||
|
** URI
|
||||||
|
|
||||||
|
------
|
||||||
|
* http://<rm http address:port>/ws/v1/cluster/apps/{appid}/appattempts
|
||||||
|
------
|
||||||
|
|
||||||
|
** HTTP Operations Supported
|
||||||
|
|
||||||
|
------
|
||||||
|
* GET
|
||||||
|
------
|
||||||
|
|
||||||
|
** Query Parameters Supported
|
||||||
|
|
||||||
|
------
|
||||||
|
None
|
||||||
|
------
|
||||||
|
|
||||||
|
** Elements of the <appAttempts> object
|
||||||
|
|
||||||
|
When you make a request for the list of app attempts, the information will be returned as an array of app attempt objects.
|
||||||
|
|
||||||
|
appAttempts:
|
||||||
|
|
||||||
|
*---------------+--------------+-------------------------------+
|
||||||
|
|| Item || Data Type || Description |
|
||||||
|
*---------------+--------------+-------------------------------+
|
||||||
|
| appAttempt | array of app attempt objects(JSON)/zero or more app attempt objects(XML) | The collection of app attempt objects |
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
|
||||||
|
** Elements of the <appAttempt> object
|
||||||
|
|
||||||
|
*---------------+--------------+-------------------------------+
|
||||||
|
|| Item || Data Type || Description |
|
||||||
|
*---------------+--------------+-------------------------------+
|
||||||
|
| id | string | The app attempt id |
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
| nodeId | string | The node id of the node the attempt ran on|
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
| nodeHttpAddress | string | The node http address of the node the attempt ran on|
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
| logsLink | string | The http link to the app attempt logs |
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
| containerId | string | The id of the container for the app attempt |
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
| startTime | long | The start time of the attempt (in ms since epoch)|
|
||||||
|
*---------------+--------------+--------------------------------+
|
||||||
|
|
||||||
|
** Response Examples
|
||||||
|
|
||||||
|
<<JSON response>>
|
||||||
|
|
||||||
|
HTTP Request:
|
||||||
|
|
||||||
|
------
|
||||||
|
GET http://<rm http address:port>/ws/v1/cluster/apps/application_1326821518301_0005/appattempts
|
||||||
|
------
|
||||||
|
|
||||||
|
Response Header:
|
||||||
|
|
||||||
|
+---+
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json
|
||||||
|
Transfer-Encoding: chunked
|
||||||
|
Server: Jetty(6.1.26)
|
||||||
|
+---+
|
||||||
|
|
||||||
|
Response Body:
|
||||||
|
|
||||||
|
+---+
|
||||||
|
{
|
||||||
|
"appAttempts" : {
|
||||||
|
"appAttempt" : [
|
||||||
|
{
|
||||||
|
"nodeId" : "host.domain.com:8041",
|
||||||
|
"nodeHttpAddress" : "host.domain.com:8042",
|
||||||
|
"startTime" : 1326381444693,
|
||||||
|
"id" : 1,
|
||||||
|
"logsLink" : "http://host.domain.com:8042/node/containerlogs/container_1326821518301_0005_01_000001/user1",
|
||||||
|
"containerId" : "container_1326821518301_0005_01_000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+---+
|
||||||
|
|
||||||
|
<<XML response>>
|
||||||
|
|
||||||
|
HTTP Request:
|
||||||
|
|
||||||
|
------
|
||||||
|
GET http://<rm http address:port>/ws/v1/cluster/apps/application_1326821518301_0005/appattempts
|
||||||
|
Accept: application/xml
|
||||||
|
------
|
||||||
|
|
||||||
|
Response Header:
|
||||||
|
|
||||||
|
+---+
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/xml
|
||||||
|
Content-Length: 575
|
||||||
|
Server: Jetty(6.1.26)
|
||||||
|
+---+
|
||||||
|
|
||||||
|
Response Body:
|
||||||
|
|
||||||
|
+---+
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<appAttempts>
|
||||||
|
<appttempt>
|
||||||
|
<nodeHttpAddress>host.domain.com:8042</nodeHttpAddress>
|
||||||
|
<nodeId>host.domain.com:8041</nodeId>
|
||||||
|
<id>1</id>
|
||||||
|
<startTime>1326381444693</startTime>
|
||||||
|
<containerId>container_1326821518301_0005_01_000001</containerId>
|
||||||
|
<logsLink>http://host.domain.com:8042/node/containerlogs/container_1326821518301_0005_01_000001/user1</logsLink>
|
||||||
|
</appAttempt>
|
||||||
|
</appAttempts>
|
||||||
|
+---+
|
||||||
|
|
||||||
* Cluster Nodes API
|
* Cluster Nodes API
|
||||||
|
|
||||||
With the Nodes API, you can obtain a collection of resources, each of which represents a node. When you run a GET operation on this resource, you obtain a collection of Node Objects.
|
With the Nodes API, you can obtain a collection of resources, each of which represents a node. When you run a GET operation on this resource, you obtain a collection of Node Objects.
|
||||||
|
|
Loading…
Reference in New Issue