YARN-5740. Add a new field in Slider status output - lifetime (remaining). Contributed by Jian He

This commit is contained in:
Gour Saha 2016-12-16 12:03:51 -08:00 committed by Jian He
parent 2cea59dc54
commit 2e1fa61253
3 changed files with 103 additions and 45 deletions

View File

@ -52,6 +52,8 @@ import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.services.api.ApplicationApi; import org.apache.hadoop.yarn.services.api.ApplicationApi;
@ -771,7 +773,7 @@ public class ApplicationApiService implements ApplicationApi {
// Get all applications in a specific state - lighter projection. For full // Get all applications in a specific state - lighter projection. For full
// detail, call getApplication on a specific app. // detail, call getApplication on a specific app.
Set<String> applications; Set<ApplicationReport> applications;
try { try {
if (StringUtils.isNotEmpty(state)) { if (StringUtils.isNotEmpty(state)) {
ApplicationStatus appStatus = new ApplicationStatus(); ApplicationStatus appStatus = new ApplicationStatus();
@ -793,13 +795,12 @@ public class ApplicationApiService implements ApplicationApi {
Set<Application> apps = new HashSet<Application>(); Set<Application> apps = new HashSet<Application>();
if (applications.size() > 0) { if (applications.size() > 0) {
try { try {
for (String app : applications) { for (ApplicationReport app : applications) {
Application application = new Application(); Application application = new Application();
// TODO: Need to get lifetime, launch-time and privileged container application.setLifetime(app.getApplicationTimeouts().get(
// status from YARN ApplicationTimeoutType.LIFETIME).getRemainingTime());
application.setLifetime(null); application.setLaunchTime(new Date(app.getStartTime()));
application.setLaunchTime(new Date()); application.setName(app.getName());
application.setName(app);
// Containers not required, setting to null to avoid empty list // Containers not required, setting to null to avoid empty list
application.setContainers(null); application.setContainers(null);
apps.add(application); apps.add(application);
@ -930,9 +931,7 @@ public class ApplicationApiService implements ApplicationApi {
app.setLaunchTime(appStatus.get("createTime") == null ? null app.setLaunchTime(appStatus.get("createTime") == null ? null
: new Date(appStatus.get("createTime").getAsLong())); : new Date(appStatus.get("createTime").getAsLong()));
// lifetime - set it to unlimited for now app.setLifetime(queryLifetime(appName));
// TODO: Once YARN-3813 and YARN-4205 are available - get it from YARN
app.setLifetime(DEFAULT_UNLIMITED_LIFETIME);
// Quicklinks // Quicklinks
Map<String, String> appQuicklinks = new HashMap<>(); Map<String, String> appQuicklinks = new HashMap<>();
@ -1062,6 +1061,24 @@ public class ApplicationApiService implements ApplicationApi {
return object.get(key) == null ? null : object.get(key).getAsJsonObject(); return object.get(key) == null ? null : object.get(key).getAsJsonObject();
} }
private long queryLifetime(String appName) {
try {
return invokeSliderClientRunnable(
new SliderClientContextRunnable<Long>() {
@Override
public Long run(SliderClient sliderClient)
throws YarnException, IOException, InterruptedException {
ApplicationReport report = sliderClient.findInstance(appName);
return report.getApplicationTimeouts()
.get(ApplicationTimeoutType.LIFETIME).getRemainingTime();
}
});
} catch (Exception e) {
logger.error("Error when querying lifetime for " + appName, e);
return DEFAULT_UNLIMITED_LIFETIME;
}
}
private JsonObject getSliderApplicationStatus(final String appName) private JsonObject getSliderApplicationStatus(final String appName)
throws IOException, YarnException, InterruptedException { throws IOException, YarnException, InterruptedException {
@ -1142,36 +1159,37 @@ public class ApplicationApiService implements ApplicationApi {
}); });
} }
private Set<String> getSliderApplications(final String state) private Set<ApplicationReport> getSliderApplications(final String state)
throws IOException, YarnException, InterruptedException { throws IOException, YarnException, InterruptedException {
return getSliderApplications(false, state); return getSliderApplications(false, state);
} }
private Set<String> getSliderApplications(final boolean liveOnly) private Set<ApplicationReport> getSliderApplications(final boolean liveOnly)
throws IOException, YarnException, InterruptedException { throws IOException, YarnException, InterruptedException {
return getSliderApplications(liveOnly, null); return getSliderApplications(liveOnly, null);
} }
private Set<String> getSliderApplications(final boolean liveOnly, private Set<ApplicationReport> getSliderApplications(final boolean liveOnly,
final String state) throws IOException, YarnException, final String state)
InterruptedException { throws IOException, YarnException, InterruptedException {
return invokeSliderClientRunnable(new SliderClientContextRunnable<Set<String>>() { return invokeSliderClientRunnable(
@Override new SliderClientContextRunnable<Set<ApplicationReport>>() {
public Set<String> run(SliderClient sliderClient) throws YarnException, @Override
IOException, InterruptedException { public Set<ApplicationReport> run(SliderClient sliderClient)
Set<String> apps; throws YarnException, IOException, InterruptedException {
ActionListArgs listArgs = new ActionListArgs(); Set<ApplicationReport> apps;
if (liveOnly) { ActionListArgs listArgs = new ActionListArgs();
apps = sliderClient.getApplicationList(null); if (liveOnly) {
} else if (StringUtils.isNotEmpty(state)) { apps = sliderClient.getApplicationList(null);
listArgs.state = state; } else if (StringUtils.isNotEmpty(state)) {
apps = sliderClient.getApplicationList(null, listArgs); listArgs.state = state;
} else { apps = sliderClient.getApplicationList(null, listArgs);
apps = sliderClient.getApplicationList(null, listArgs); } else {
} apps = sliderClient.getApplicationList(null, listArgs);
return apps; }
} return apps;
}); }
});
} }
@DELETE @DELETE

View File

@ -55,6 +55,7 @@ import org.apache.hadoop.yarn.api.ApplicationConstants;
import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationTimeoutsRequest; import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationTimeoutsRequest;
import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ApplicationReport; import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.ApplicationTimeout;
import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType; import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
import org.apache.hadoop.yarn.api.records.LocalResource; import org.apache.hadoop.yarn.api.records.LocalResource;
@ -178,6 +179,7 @@ import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.Console; import java.io.Console;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -185,6 +187,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@ -2706,11 +2709,12 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
@Override @Override
public int actionList(String clustername, ActionListArgs args) public int actionList(String clustername, ActionListArgs args)
throws IOException, YarnException { throws IOException, YarnException {
Set<String> appInstances = getApplicationList(clustername, args); Set<ApplicationReport> appInstances = getApplicationList(clustername, args);
// getApplicationList never returns null if (!appInstances.isEmpty()) {
return !appInstances.isEmpty() ? EXIT_SUCCESS return EXIT_SUCCESS;
: ((appInstances.isEmpty() && isUnset(clustername)) ? EXIT_SUCCESS } else {
: EXIT_FALSE); return EXIT_FALSE;
}
} }
/** /**
@ -2723,8 +2727,8 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
* @throws IOException * @throws IOException
* @throws YarnException * @throws YarnException
*/ */
public Set<String> getApplicationList(String clustername) throws IOException, public Set<ApplicationReport> getApplicationList(String clustername)
YarnException { throws IOException, YarnException {
ActionListArgs args = new ActionListArgs(); ActionListArgs args = new ActionListArgs();
args.live = true; args.live = true;
return getApplicationList(clustername, args); return getApplicationList(clustername, args);
@ -2743,8 +2747,8 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
* @throws UnknownApplicationInstanceException * @throws UnknownApplicationInstanceException
* if a specific instance was named but it was not found * if a specific instance was named but it was not found
*/ */
public Set<String> getApplicationList(String clustername, ActionListArgs args) public Set<ApplicationReport> getApplicationList(String clustername,
throws IOException, YarnException { ActionListArgs args) throws IOException, YarnException {
if (args.help) { if (args.help) {
actionHelp(ACTION_LIST); actionHelp(ACTION_LIST);
// the above call throws an exception so the return is not really required // the above call throws an exception so the return is not really required
@ -2830,13 +2834,13 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
} }
// at this point there is either the entire list or a stripped down instance // at this point there is either the entire list or a stripped down instance
Set<String> listedInstances = new HashSet<String>(); Set<ApplicationReport> listedInstances = new HashSet<ApplicationReport>();
for (String name : persistentInstances.keySet()) { for (String name : persistentInstances.keySet()) {
ApplicationReport report = reportMap.get(name); ApplicationReport report = reportMap.get(name);
if (!listOnlyInState || report != null) { if (!listOnlyInState || report != null) {
// list the details if all were requested, or the filtering contained // list the details if all were requested, or the filtering contained
// a report // a report
listedInstances.add(name); listedInstances.add(report);
// containers will be non-null when only one instance is requested // containers will be non-null when only one instance is requested
String details = instanceDetailsToString(name, report, String details = instanceDetailsToString(name, report,
containers, version, components, verbose); containers, version, components, verbose);
@ -3055,7 +3059,7 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
* @throws YarnException YARN issues * @throws YarnException YARN issues
* @throws IOException IO problems * @throws IOException IO problems
*/ */
private ApplicationReport findInstance(String appname) public ApplicationReport findInstance(String appname)
throws YarnException, IOException { throws YarnException, IOException {
return yarnAppListClient.findInstance(appname); return yarnAppListClient.findInstance(appname);
} }
@ -3106,6 +3110,11 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
@VisibleForTesting @VisibleForTesting
public int actionStatus(String clustername, ActionStatusArgs statusArgs) public int actionStatus(String clustername, ActionStatusArgs statusArgs)
throws YarnException, IOException { throws YarnException, IOException {
if (statusArgs.lifetime) {
queryAndPrintLifetime(clustername);
return EXIT_SUCCESS;
}
ClusterDescription status = verifyAndGetClusterDescription(clustername); ClusterDescription status = verifyAndGetClusterDescription(clustername);
String outfile = statusArgs.getOutput(); String outfile = statusArgs.getOutput();
if (outfile == null) { if (outfile == null) {
@ -3122,6 +3131,32 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
return verifyAndGetClusterDescription(clustername).toJsonString(); return verifyAndGetClusterDescription(clustername).toJsonString();
} }
private void queryAndPrintLifetime(String appName)
throws YarnException, IOException {
ApplicationReport appReport = findInstance(appName);
if (appReport == null) {
throw new YarnException("No application found for " + appName);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter timeoutStr =
new PrintWriter(new OutputStreamWriter(baos, Charset.forName("UTF-8")));
try {
ApplicationTimeout lifetime = appReport.getApplicationTimeouts()
.get(ApplicationTimeoutType.LIFETIME);
if (lifetime.getRemainingTime() == -1L) {
timeoutStr.append(appName + " has no lifetime configured.");
} else {
timeoutStr.append("\t" + ApplicationTimeoutType.LIFETIME);
timeoutStr.print(" expires at : " + lifetime.getExpiryTime());
timeoutStr.println(
".\tRemaining Time : " + lifetime.getRemainingTime() + " seconds");
}
System.out.println(baos.toString("UTF-8"));
} finally {
timeoutStr.close();
}
}
private ClusterDescription verifyAndGetClusterDescription(String clustername) private ClusterDescription verifyAndGetClusterDescription(String clustername)
throws YarnException, IOException { throws YarnException, IOException {
verifyBindingsDefined(); verifyBindingsDefined();
@ -3547,7 +3582,8 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe
* @throws IOException * @throws IOException
*/ */
@VisibleForTesting @VisibleForTesting
public List<ApplicationReport> getApplications() throws YarnException, IOException { public List<ApplicationReport> getApplications()
throws YarnException, IOException {
return yarnClient.getApplications(); return yarnClient.getApplications();
} }

View File

@ -35,6 +35,10 @@ public class ActionStatusArgs extends AbstractActionArgs {
description = "Output file for the status information") description = "Output file for the status information")
public String output; public String output;
@Parameter(names = {ARG_LIFETIME},
description = "Lifetime of the application from the time of request")
public boolean lifetime;
public String getOutput() { public String getOutput() {
return output; return output;
} }