diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java index e65744b..507fc80 100644 --- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/main/java/org/apache/hadoop/mapred/ResourceMgrDelegate.java @@ -283,9 +283,15 @@ public YarnClientApplication createApplication() throws } @Override + public void killApplication(ApplicationId applicationId, String reason) + throws YarnException, IOException { + client.killApplication(applicationId, reason); + } + + @Override public void killApplication(ApplicationId applicationId) throws YarnException, IOException { - client.killApplication(applicationId); + killApplication(applicationId, null); } @Override diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/KillApplicationRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/KillApplicationRequest.java index 606cf4e..26a5a9d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/KillApplicationRequest.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/KillApplicationRequest.java @@ -20,6 +20,7 @@ import org.apache.hadoop.classification.InterfaceAudience.Public; import org.apache.hadoop.classification.InterfaceStability.Stable; +import org.apache.hadoop.classification.InterfaceStability.Evolving; import org.apache.hadoop.yarn.api.ApplicationClientProtocol; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.util.Records; @@ -53,8 +54,26 @@ public static KillApplicationRequest newInstance(ApplicationId applicationId) { @Public @Stable public abstract ApplicationId getApplicationId(); - + + /** + * Set the ApplicationId of the application to be aborted. + */ @Public @Stable public abstract void setApplicationId(ApplicationId applicationId); + + /** + * Get the diagnostic Reason for the application abort. + * @return Reason for the application abort. + */ + @Public + @Evolving + public abstract String getReason(); + + /** + * Set the diagnostic Reason for the application abort. + */ + @Public + @Evolving + public abstract void setReason(String reason); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java index 8c8ad16..0487629 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java @@ -58,6 +58,9 @@ @Evolving public static final int APPLICATION_MAX_TAG_LENGTH = 100; + @Evolving + public static final int MAX_KILL_REASON_LENGTH = 128; + private static final String YARN_DEFAULT_XML_FILE = "yarn-default.xml"; static { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto index eff5cd7..faf5d66 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/proto/yarn_service_protos.proto @@ -115,6 +115,7 @@ message SubmitApplicationResponseProto { message KillApplicationRequestProto { optional ApplicationIdProto application_id = 1; + optional string reason = 2; } message KillApplicationResponseProto { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java index c6db3ab..9a7333a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/YarnClient.java @@ -106,6 +106,25 @@ public abstract ApplicationId submitApplication(ApplicationSubmissionContext app * * @param applicationId * {@link ApplicationId} of the application that needs to be killed + * @param reason justification for application kill. Callers are expected to + * use the same reason for repeated invocation attempts with the same + * application id. + * @throws YarnException + * in case of errors or if YARN rejects the request due to + * access-control restrictions. + * @throws IOException + * @see #getQueueAclsInfo() + */ + public abstract void killApplication(ApplicationId applicationId, + String reason) throws YarnException, IOException; + + /** + *

+ * Kill an application identified by given ID. + *

+ * + * @param applicationId + * {@link ApplicationId} of the application that needs to be killed * @throws YarnException * in case of errors or if YARN rejects the request due to * access-control restrictions. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/YarnClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/YarnClientImpl.java index feb3bb7..3c10d74 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/YarnClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/api/impl/YarnClientImpl.java @@ -218,9 +218,16 @@ public YarnClientApplication createApplication() @Override public void killApplication(ApplicationId applicationId) throws YarnException, IOException { + killApplication(applicationId, null); + } + + @Override + public void killApplication(ApplicationId applicationId, String reason) + throws YarnException, IOException { KillApplicationRequest request = Records.newRecord(KillApplicationRequest.class); request.setApplicationId(applicationId); + request.setReason(reason); try { int pollCount = 0; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/ApplicationCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/ApplicationCLI.java index 4332f5b..96ee706 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/ApplicationCLI.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/ApplicationCLI.java @@ -96,7 +96,10 @@ public int run(String[] args) throws Exception { + "based on application type, " + "and -appStates to filter applications based on application state"); } - opts.addOption(KILL_CMD, true, "Kills the application."); + Option killOption = new Option(KILL_CMD, true, "Kills the application."); + killOption.setArgs(2); + killOption.setArgName("Application ID [reason]"); + opts.addOption(killOption); opts.addOption(MOVE_TO_QUEUE_CMD, true, "Moves the application to a " + "different queue."); opts.addOption(QUEUE_CMD, true, "Works with the movetoqueue command to" @@ -116,7 +119,6 @@ public int run(String[] args) throws Exception { appStateOpt.setArgs(Option.UNLIMITED_VALUES); appStateOpt.setArgName("States"); opts.addOption(appStateOpt); - opts.getOption(KILL_CMD).setArgName("Application ID"); opts.getOption(MOVE_TO_QUEUE_CMD).setArgName("Application ID"); opts.getOption(QUEUE_CMD).setArgName("Queue Name"); opts.getOption(STATUS_CMD).setArgName("Application ID"); @@ -204,11 +206,12 @@ public int run(String[] args) throws Exception { listApplications(appTypes, appStates); } } else if (cliParser.hasOption(KILL_CMD)) { - if (args.length != 3) { + if (args.length < 3 || args.length > 4) { printUsage(opts); return exitCode; } - killApplication(cliParser.getOptionValue(KILL_CMD)); + final String[] killArgs = cliParser.getOptionValues(KILL_CMD); + killApplication(killArgs[0], killArgs.length == 2 ? killArgs[1] : null); } else if (cliParser.hasOption(MOVE_TO_QUEUE_CMD)) { if (!cliParser.hasOption(QUEUE_CMD)) { printUsage(opts); @@ -364,11 +367,12 @@ private void listApplications(Set appTypes, * Kills the application with the application id as appId * * @param applicationId + * @param reason * @throws YarnException * @throws IOException */ - private void killApplication(String applicationId) throws YarnException, - IOException { + private void killApplication(String applicationId, String reason) + throws YarnException, IOException { ApplicationId appId = ConverterUtils.toApplicationId(applicationId); ApplicationReport appReport = client.getApplicationReport(appId); if (appReport.getYarnApplicationState() == YarnApplicationState.FINISHED @@ -377,7 +381,7 @@ private void killApplication(String applicationId) throws YarnException, sysout.println("Application " + applicationId + " has already finished "); } else { sysout.println("Killing application " + applicationId); - client.killApplication(appId); + client.killApplication(appId, reason); } } @@ -455,18 +459,17 @@ private void printApplicationReport(String applicationId) private String getAllValidApplicationStates() { StringBuilder sb = new StringBuilder(); sb.append("The valid application state can be" + " one of the following: "); - sb.append(ALLSTATES_OPTION + ","); + sb.append(ALLSTATES_OPTION); for (YarnApplicationState appState : YarnApplicationState.values()) { - sb.append(appState + ","); + sb.append(", " + appState); } - String output = sb.toString(); - return output.substring(0, output.length() - 1); + return sb.toString(); } /** * Lists the application attempts matching the given applicationid * - * @param applicationId + * @param appId * @throws YarnException * @throws IOException */ diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestYarnClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestYarnClient.java index 7c34966..7db729c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestYarnClient.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/api/impl/TestYarnClient.java @@ -18,8 +18,8 @@ package org.apache.hadoop.yarn.client.api.impl; -import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -68,6 +68,8 @@ import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; import org.junit.Test; public class TestYarnClient { @@ -133,6 +135,12 @@ public void testSubmitApplication() { @Test public void testKillApplication() throws Exception { + testKillApplicationInternal(null); + testKillApplicationInternal("TestKillAppReason"); + } + + private void testKillApplicationInternal(final String reason) + throws Exception { MockRM rm = new MockRM(); rm.start(); RMApp app = rm.submitApp(2000); @@ -142,10 +150,29 @@ public void testKillApplication() throws Exception { final YarnClient client = new MockYarnClient(); client.init(conf); client.start(); + if (reason == null) { + client.killApplication(app.getApplicationId()); + } else { + client.killApplication(app.getApplicationId(), reason); + } + + BaseMatcher bm = + new BaseMatcher() { + + @Override + public void describeTo(Description decs) {} + + @Override + public boolean matches(Object o) { + KillApplicationRequest req = (KillApplicationRequest)o; + final String reqReason = req.getReason(); + return reason == reqReason + || reason != null && reason.contains(reqReason); + } + }; - client.killApplication(app.getApplicationId()); verify(((MockYarnClient) client).getRMClient(), times(2)) - .forceKillApplication(any(KillApplicationRequest.class)); + .forceKillApplication((argThat(bm))); } @Test(timeout = 30000) diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java index 9772186..c6996c0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestYarnCLI.java @@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -29,15 +31,16 @@ import static org.mockito.Mockito.doThrow; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Date; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; import junit.framework.Assert; @@ -67,6 +70,10 @@ import org.apache.commons.cli.Options; public class TestYarnCLI { + private static final Pattern SPACES_PATTERN = + Pattern.compile("\\s+|\\n+|\\t+"); + private static final String APP_HELP = createApplicationCLIHelpMessage(); + private static final String NODE_HELP = createNodeCLIHelpMessage(); private YarnClient client = mock(YarnClient.class); ByteArrayOutputStream sysOutStream; @@ -534,12 +541,11 @@ public void testGetApplications() throws Exception { pw.println("The application state INVALID is invalid."); pw.print("The valid application state can be one of the following: "); StringBuilder sb = new StringBuilder(); - sb.append("ALL,"); + sb.append("ALL"); for(YarnApplicationState state : YarnApplicationState.values()) { - sb.append(state+","); + sb.append(", " + state); } - String output = sb.toString(); - pw.println(output.substring(0, output.length()-1)); + pw.println(sb.toString()); pw.close(); appsReportStr = baos.toString("UTF-8"); Assert.assertEquals(appsReportStr, sysOutStream.toString()); @@ -675,23 +681,25 @@ public void testAppsHelpCommand() throws Exception { int result = spyCli.run(new String[] { "-help" }); Assert.assertTrue(result == 0); verify(spyCli).printUsage(any(Options.class)); - Assert.assertEquals(createApplicationCLIHelpMessage(), - sysOutStream.toString()); + Assert.assertEquals(APP_HELP, normalize(sysOutStream.toString())); + // too many args for kill + // sysOutStream.reset(); ApplicationId applicationId = ApplicationId.newInstance(1234, 5); result = - cli.run(new String[] {"application", "-kill", applicationId.toString(), "args" }); + cli.run(new String[] {"application", "-kill", applicationId.toString(), + "args2", "args3" }); + Assert.assertSame("Exit code", -1, result); verify(spyCli).printUsage(any(Options.class)); - Assert.assertEquals(createApplicationCLIHelpMessage(), - sysOutStream.toString()); + Assert.assertEquals(APP_HELP, normalize(sysOutStream.toString())); sysOutStream.reset(); NodeId nodeId = NodeId.newInstance("host0", 0); result = cli.run(new String[] { "-status", nodeId.toString(), "args" }); + Assert.assertSame("Exit code", -1, result); verify(spyCli).printUsage(any(Options.class)); - Assert.assertEquals(createApplicationCLIHelpMessage(), - sysOutStream.toString()); + Assert.assertEquals(APP_HELP, normalize(sysOutStream.toString())); } @Test (timeout = 5000) @@ -701,8 +709,7 @@ public void testNodesHelpCommand() throws Exception { nodeCLI.setSysOutPrintStream(sysOut); nodeCLI.setSysErrPrintStream(sysErr); nodeCLI.run(new String[] {}); - Assert.assertEquals(createNodeCLIHelpMessage(), - sysOutStream.toString()); + Assert.assertEquals(NODE_HELP, normalize(sysOutStream.toString())); } @Test @@ -710,31 +717,46 @@ public void testKillApplication() throws Exception { ApplicationCLI cli = createAndGetAppCLI(); ApplicationId applicationId = ApplicationId.newInstance(1234, 5); - ApplicationReport newApplicationReport2 = ApplicationReport.newInstance( + ApplicationReport newApplicationReport1 = ApplicationReport.newInstance( applicationId, ApplicationAttemptId.newInstance(applicationId, 1), "user", "queue", "appname", "host", 124, null, YarnApplicationState.FINISHED, "diagnostics", "url", 0, 0, FinalApplicationStatus.SUCCEEDED, null, "N/A", 0.53789f, "YARN", null); when(client.getApplicationReport(any(ApplicationId.class))).thenReturn( - newApplicationReport2); + newApplicationReport1); int result = cli.run(new String[] { "application","-kill", applicationId.toString() }); assertEquals(0, result); verify(client, times(0)).killApplication(any(ApplicationId.class)); verify(sysOut).println( "Application " + applicationId + " has already finished "); - ApplicationReport newApplicationReport = ApplicationReport.newInstance( - applicationId, ApplicationAttemptId.newInstance(applicationId, 1), + ApplicationReport newApplicationReport2 = ApplicationReport.newInstance( + applicationId, ApplicationAttemptId.newInstance(applicationId, 2), "user", "queue", "appname", "host", 124, null, YarnApplicationState.RUNNING, "diagnostics", "url", 0, 0, FinalApplicationStatus.SUCCEEDED, null, "N/A", 0.53789f, "YARN", null); when(client.getApplicationReport(any(ApplicationId.class))).thenReturn( - newApplicationReport); + newApplicationReport2); result = cli.run(new String[] { "application","-kill", applicationId.toString() }); assertEquals(0, result); - verify(client).killApplication(any(ApplicationId.class)); + verify(client).killApplication(any(ApplicationId.class), anyString()); verify(sysOut).println("Killing application application_1234_0005"); + ApplicationReport newApplicationReport3 = ApplicationReport.newInstance( + applicationId, ApplicationAttemptId.newInstance(applicationId, 3), + "user", "queue", "appname", "host", 124, null, + YarnApplicationState.RUNNING, "diagnostics", "url", 0, 0, + FinalApplicationStatus.SUCCEEDED, null, "N/A", 0.53789f, "YARN", null); + when(client.getApplicationReport(any(ApplicationId.class))).thenReturn( + newApplicationReport3); + final String reason = "TestKillAppReason"; + result = cli.run(new String[] { "application", "-kill", + applicationId.toString(), reason}); + assertEquals(0, result); + verify(client).killApplication(any(ApplicationId.class), eq(reason)); + verify(sysOut, times(2)) + .println("Killing application application_1234_0005"); + doThrow(new ApplicationNotFoundException("Application with id '" + applicationId + "' doesn't exist in RM.")).when(client) .getApplicationReport(applicationId); @@ -1093,8 +1115,8 @@ public void testMissingArguments() throws Exception { ApplicationCLI cli = createAndGetAppCLI(); int result = cli.run(new String[] { "-status" }); Assert.assertEquals(result, -1); - Assert.assertEquals(String.format("Missing argument for options%n%1s", - createApplicationCLIHelpMessage()), sysOutStream.toString()); + Assert.assertEquals("Missing argument for options " + APP_HELP, + normalize(sysOutStream.toString())); sysOutStream.reset(); NodeCLI nodeCLI = new NodeCLI(); @@ -1103,8 +1125,8 @@ public void testMissingArguments() throws Exception { nodeCLI.setSysErrPrintStream(sysErr); result = nodeCLI.run(new String[] { "-status" }); Assert.assertEquals(result, -1); - Assert.assertEquals(String.format("Missing argument for options%n%1s", - createNodeCLIHelpMessage()), sysOutStream.toString()); + Assert.assertEquals("Missing argument for options " + NODE_HELP, + normalize(sysOutStream.toString())); } private void verifyUsageInfo(YarnCLI cli) throws Exception { @@ -1133,7 +1155,7 @@ private ApplicationCLI createAndGetAppCLI() { return cli; } - private String createApplicationCLIHelpMessage() throws IOException { + private static String createApplicationCLIHelpMessage() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter pw = new PrintWriter(baos); pw.println("usage: application"); @@ -1141,13 +1163,13 @@ private String createApplicationCLIHelpMessage() throws IOException { pw.println(" based on input comma-separated list of"); pw.println(" application states. The valid application"); pw.println(" state can be one of the following:"); - pw.println(" ALL,NEW,NEW_SAVING,SUBMITTED,ACCEPTED,RUN"); - pw.println(" NING,FINISHED,FAILED,KILLED"); + pw.println(" ALL, NEW, NEW_SAVING, SUBMITTED, ACCEPTED, RUNNING,"); + pw.println(" FINISHED, FAILED, KILLED"); pw.println(" -appTypes Works with -list to filter applications"); pw.println(" based on input comma-separated list of"); pw.println(" application types."); pw.println(" -help Displays help for all commands."); - pw.println(" -kill Kills the application."); + pw.println(" -kill Kills the application."); pw.println(" -list List applications from the RM. Supports"); pw.println(" optional use of -appTypes to filter"); pw.println(" applications based on application type,"); @@ -1160,11 +1182,15 @@ private String createApplicationCLIHelpMessage() throws IOException { pw.println(" application to."); pw.println(" -status Prints the status of the application."); pw.close(); - String appsHelpStr = baos.toString("UTF-8"); - return appsHelpStr; + + try { + return normalize(baos.toString("UTF-8")); + } catch (UnsupportedEncodingException infeasible) { + return infeasible.toString(); + } } - private String createNodeCLIHelpMessage() throws IOException { + private static String createNodeCLIHelpMessage() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter pw = new PrintWriter(baos); pw.println("usage: node"); @@ -1176,7 +1202,15 @@ private String createNodeCLIHelpMessage() throws IOException { pw.println(" comma-separated list of node states."); pw.println(" -status Prints the status report of the node."); pw.close(); - String nodesHelpStr = baos.toString("UTF-8"); - return nodesHelpStr; + + try { + return normalize(baos.toString("UTF-8")); + } catch (UnsupportedEncodingException infeasible) { + return infeasible.toString(); + } + } + + private static String normalize(String s) { + return SPACES_PATTERN.matcher(s).replaceAll(" "); // single space } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/KillApplicationRequestPBImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/KillApplicationRequestPBImpl.java index db97367..99ca603 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/KillApplicationRequestPBImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/KillApplicationRequestPBImpl.java @@ -38,8 +38,8 @@ boolean viaProto = false; private ApplicationId applicationId = null; - - + private String reason; + public KillApplicationRequestPBImpl() { builder = KillApplicationRequestProto.newBuilder(); } @@ -80,6 +80,9 @@ private void mergeLocalToBuilder() { if (this.applicationId != null) { builder.setApplicationId(convertToProtoFormat(this.applicationId)); } + if (reason != null) { + builder.setReason(reason); + } } private void mergeLocalToProto() { @@ -119,6 +122,27 @@ public void setApplicationId(ApplicationId applicationId) { this.applicationId = applicationId; } + @Override + public String getReason() { + if (reason != null) { + return reason; + } + final KillApplicationRequestProtoOrBuilder p = viaProto ? proto : builder; + if (p.hasReason()) { + reason = p.getReason(); + } + return reason; + } + + @Override + public void setReason(String reason) { + maybeInitBuilder(); + if (reason == null) { + builder.clearReason(); + } + this.reason = reason; + } + private ApplicationIdPBImpl convertFromProtoFormat(ApplicationIdProto p) { return new ApplicationIdPBImpl(p); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java index 2f8526a..b41f995 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java @@ -94,8 +94,7 @@ import org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger.AuditConstants; 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.RMAppKillEvent; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppMoveEvent; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState; import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode; @@ -362,6 +361,13 @@ public KillApplicationResponse forceKillApplication( KillApplicationRequest request) throws YarnException { ApplicationId applicationId = request.getApplicationId(); + String reason = request.getReason(); + if (reason != null) { + if (reason.length() > YarnConfiguration.MAX_KILL_REASON_LENGTH) { + reason = reason.substring(0, YarnConfiguration.MAX_KILL_REASON_LENGTH); + request.setReason(reason); + } + } UserGroupInformation callerUGI; try { @@ -401,7 +407,7 @@ public KillApplicationResponse forceKillApplication( return KillApplicationResponse.newInstance(true); } else { this.rmContext.getDispatcher().getEventHandler() - .handle(new RMAppEvent(applicationId, RMAppEventType.KILL)); + .handle(new RMAppKillEvent(applicationId, reason)); return KillApplicationResponse.newInstance(false); } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java index 196e89d..daf6c58 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppImpl.java @@ -112,6 +112,7 @@ private long storedFinishTime = 0; private RMAppAttempt currentAttempt; private String queue; + private boolean killDiagsAdded; @SuppressWarnings("rawtypes") private EventHandler handler; private static final FinalTransition FINAL_TRANSITION = new FinalTransition(); @@ -893,7 +894,12 @@ private void rememberTargetTransitionsAndStoreState(RMAppEvent event, diags = getAppAttemptFailedDiagnostics(failedEvent); break; case ATTEMPT_KILLED: - diags = getAppKilledDiagnostics(); + if (killDiagsAdded) { + diags = getDiagnostics().toString(); + } else { + killDiagsAdded = true; + diags = getDiagnostics().append(getAppKilledDiagnostics()).toString(); + } break; default: break; @@ -982,7 +988,11 @@ public void transition(RMAppImpl app, RMAppEvent event) { private static class AppKilledTransition extends FinalTransition { @Override public void transition(RMAppImpl app, RMAppEvent event) { - app.diagnostics.append(getAppKilledDiagnostics()); + app.addUserReason(event); + if (!app.killDiagsAdded) { + app.killDiagsAdded = true; + app.diagnostics.append(getAppKilledDiagnostics()); + } super.transition(app, event); }; } @@ -994,6 +1004,7 @@ private static String getAppKilledDiagnostics() { private static class KillAttemptTransition extends RMAppTransition { @Override public void transition(RMAppImpl app, RMAppEvent event) { + app.addUserReason(event); app.stateBeforeKilling = app.getState(); app.handler.handle(new RMAppAttemptEvent(app.currentAttempt .getAppAttemptId(), RMAppAttemptEventType.KILL)); @@ -1080,6 +1091,16 @@ public RMAppState transition(RMAppImpl app, RMAppEvent event) { } } + private void addUserReason(RMAppEvent event) { + if (event.getType() == RMAppEventType.KILL) { + final RMAppKillEvent killEvent = (RMAppKillEvent)event; + final String reason = killEvent.getReason(); + if (reason != null) { + diagnostics.append("user diagnostics: \"" + reason + "\"; "); + } + } + } + @Override public String getApplicationType() { return this.applicationType; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppKillEvent.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppKillEvent.java new file mode 100644 index 0000000..98abea6 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMAppKillEvent.java @@ -0,0 +1,37 @@ +/** + * 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.rmapp; + +import org.apache.hadoop.yarn.api.records.ApplicationId; + +public class RMAppKillEvent extends RMAppEvent { + private final String reason; + + public RMAppKillEvent(ApplicationId applicationId, String reason) { + super(applicationId, RMAppEventType.KILL); + this.reason = reason; + } + + public RMAppKillEvent(ApplicationId applicationId) { + this(applicationId, null); + } + + public String getReason() { + return reason; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java index 7c49681..28c4055 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java @@ -44,7 +44,6 @@ import com.google.common.collect.Sets; import junit.framework.Assert; -import org.apache.commons.lang.math.LongRange; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -75,7 +74,6 @@ import org.apache.hadoop.yarn.api.records.QueueACL; import org.apache.hadoop.yarn.api.records.QueueInfo; import org.apache.hadoop.yarn.api.records.Resource; -import org.apache.hadoop.yarn.api.records.YarnApplicationState; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.event.Dispatcher; import org.apache.hadoop.yarn.event.Event; @@ -228,6 +226,7 @@ public void testForceKillApplication() throws YarnException { BuilderUtils.newApplicationId(System.currentTimeMillis(), 0); KillApplicationRequest request = KillApplicationRequest.newInstance(applicationId); + request.setReason("ForceKillReason"); try { rmService.forceKillApplication(request); Assert.fail(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java index 58482ee..e489b1e 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java @@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.server.resourcemanager.rmapp; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; @@ -57,7 +58,6 @@ import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptEvent; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptEventType; -import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptState; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.event.RMAppAttemptUpdateSavedEvent; import org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.ContainerAllocationExpirer; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler; @@ -291,31 +291,25 @@ private void assertTimesAtFinish(RMApp application) { (application.getFinishTime() >= application.getStartTime())); } - private void assertAppFinalStateSaved(RMApp application){ + private void assertAppFinalStateSaved(){ verify(store, times(1)).updateApplicationState(any(ApplicationState.class)); } - private void assertAppFinalStateNotSaved(RMApp application){ + private void assertAppFinalStateNotSaved(){ verify(store, times(0)).updateApplicationState(any(ApplicationState.class)); } - private void assertKilled(RMApp application) { + private void assertKilled(RMApp application, String reason) { assertTimesAtFinish(application); assertAppState(RMAppState.KILLED, application); assertFinalAppStatus(FinalApplicationStatus.KILLED, application); - StringBuilder diag = application.getDiagnostics(); - Assert.assertEquals("application diagnostics is not correct", - "Application killed by user.", diag.toString()); - } - - private void assertAppAndAttemptKilled(RMApp application) - throws InterruptedException { - sendAttemptUpdateSavedEvent(application); - sendAppUpdateSavedEvent(application); - assertKilled(application); - Assert.assertEquals(RMAppAttemptState.KILLED, application - .getCurrentAppAttempt().getAppAttemptState()); - assertAppFinalStateSaved(application); + final String diag = application.getDiagnostics().toString(); + Assert.assertTrue("application diagnostics is not correct", + diag.contains("Application killed by user.")); + if (reason != null) { + Assert.assertTrue("application diagnostics is not correct", + diag.contains(reason)); + } } private void assertFailed(RMApp application, String regex) { @@ -342,8 +336,8 @@ private void sendAttemptUpdateSavedEvent(RMApp application) { protected RMApp testCreateAppNewSaving( ApplicationSubmissionContext submissionContext) throws IOException { - RMApp application = createNewTestApp(submissionContext); - verify(writer).applicationStarted(any(RMApp.class)); + RMApp application = createNewTestApp(submissionContext); + verify(writer).applicationStarted(eq(application)); // NEW => NEW_SAVING event RMAppEventType.START RMAppEvent event = new RMAppEvent(application.getApplicationId(), RMAppEventType.START); @@ -412,7 +406,7 @@ protected RMApp testCreateAppFinalSaving( RMAppEventType.ATTEMPT_UNREGISTERED); application.handle(finishingEvent); assertAppState(RMAppState.FINAL_SAVING, application); - assertAppFinalStateSaved(application); + assertAppFinalStateSaved(); return application; } @@ -466,7 +460,7 @@ public void testUnmanagedApp() throws IOException { application.getDiagnostics().indexOf(diagMsg) != -1); // reset the counter of Mockito.verify - reset(writer); + reset(writer, store); // test app fails after 1 app attempt failure LOG.info("--- START: testUnmanagedAppFailPath ---"); @@ -480,7 +474,7 @@ public void testUnmanagedApp() throws IOException { sendAppUpdateSavedEvent(application); assertFailed(application, ".*Unmanaged application.*Failing the application.*"); - assertAppFinalStateSaved(application); + assertAppFinalStateSaved(); } @Test @@ -500,18 +494,24 @@ public void testAppRecoverPath() throws IOException { @Test (timeout = 30000) public void testAppNewKill() throws IOException { - LOG.info("--- START: testAppNewKill ---"); + testAppNewKillInternal("TestAppKillReason"); + reset(writer, store); + testAppNewKillInternal(null); + } + + private void testAppNewKillInternal(String reason) { + LOG.info("--- START: testAppNewKill " + reason + " ---"); RMApp application = createNewTestApp(null); // NEW => KILLED event RMAppEventType.KILL - RMAppEvent event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + RMAppEvent event = + new RMAppKillEvent(application.getApplicationId(), reason); application.handle(event); rmDispatcher.await(); sendAppUpdateSavedEvent(application); - assertKilled(application); - assertAppFinalStateNotSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertKilled(application, reason); + assertAppFinalStateNotSaved(); + verify(writer).applicationFinished(eq(application)); } @Test @@ -527,23 +527,29 @@ public void testAppNewReject() throws IOException { rmDispatcher.await(); sendAppUpdateSavedEvent(application); assertFailed(application, rejectedText); - assertAppFinalStateNotSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertAppFinalStateNotSaved(); + verify(writer).applicationFinished(eq(application)); } @Test (timeout = 30000) public void testAppNewSavingKill() throws IOException { - LOG.info("--- START: testAppNewSavingKill ---"); + testAppNewSavingKillInternal("TestAppKillReason"); + reset(writer, store); + testAppNewSavingKillInternal(null); + } + + private void testAppNewSavingKillInternal(String reason) throws IOException { + LOG.info("--- START: testAppNewSavingKill " + reason + " ---"); RMApp application = testCreateAppNewSaving(null); // NEW_SAVING => KILLED event RMAppEventType.KILL RMAppEvent event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + new RMAppKillEvent(application.getApplicationId(), reason); application.handle(event); rmDispatcher.await(); sendAppUpdateSavedEvent(application); - assertKilled(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertKilled(application, reason); + verify(writer).applicationFinished(eq(application)); } @Test (timeout = 30000) @@ -559,8 +565,8 @@ public void testAppNewSavingReject() throws IOException { rmDispatcher.await(); sendAppUpdateSavedEvent(application); assertFailed(application, rejectedText); - assertAppFinalStateSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertAppFinalStateSaved(); + verify(writer).applicationFinished(eq(application)); } @Test (timeout = 30000) @@ -576,23 +582,29 @@ public void testAppSubmittedRejected() throws IOException { rmDispatcher.await(); sendAppUpdateSavedEvent(application); assertFailed(application, rejectedText); - assertAppFinalStateSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertAppFinalStateSaved(); + verify(writer).applicationFinished(eq(application)); } @Test public void testAppSubmittedKill() throws IOException, InterruptedException { - LOG.info("--- START: testAppSubmittedKill---"); + testAppSubmittedKillInternal("TestAppKillReason"); + reset(writer, store); + testAppSubmittedKillInternal(null); + } + + private void testAppSubmittedKillInternal(String reason) throws IOException { + LOG.info("--- START: testAppSubmittedKill " + reason + " ---"); RMApp application = testCreateAppSubmittedNoRecovery(null); // SUBMITTED => KILLED event RMAppEventType.KILL - RMAppEvent event = new RMAppEvent(application.getApplicationId(), - RMAppEventType.KILL); + RMAppEvent event = + new RMAppKillEvent(application.getApplicationId(), reason); application.handle(event); rmDispatcher.await(); sendAppUpdateSavedEvent(application); - assertKilled(application); - assertAppFinalStateSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertKilled(application, reason); + assertAppFinalStateSaved(); + verify(writer).applicationFinished(eq(application)); } @Test @@ -626,17 +638,23 @@ public void testAppAcceptedFailed() throws IOException { rmDispatcher.await(); sendAppUpdateSavedEvent(application); assertFailed(application, ".*" + message + ".*Failing the application.*"); - assertAppFinalStateSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertAppFinalStateSaved(); + verify(writer).applicationFinished(eq(application)); } @Test public void testAppAcceptedKill() throws IOException, InterruptedException { - LOG.info("--- START: testAppAcceptedKill ---"); + testAppAcceptedKillInternal("TestAppKillReason"); + reset(writer, store); + testAppAcceptedKillInternal(null); + } + + private void testAppAcceptedKillInternal(String reason) throws IOException { + LOG.info("--- START: testAppAcceptedKill " + reason + " ---"); RMApp application = testCreateAppAccepted(null); // ACCEPTED => KILLED event RMAppEventType.KILL - RMAppEvent event = new RMAppEvent(application.getApplicationId(), - RMAppEventType.KILL); + RMAppEvent event = + new RMAppKillEvent(application.getApplicationId(), reason); application.handle(event); rmDispatcher.await(); @@ -647,19 +665,24 @@ public void testAppAcceptedKill() throws IOException, InterruptedException { application.handle(appAttemptKilled); assertAppState(RMAppState.FINAL_SAVING, application); sendAppUpdateSavedEvent(application); - assertKilled(application); - assertAppFinalStateSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertKilled(application, reason); + assertAppFinalStateSaved(); + verify(writer).applicationFinished(eq(application)); } @Test public void testAppRunningKill() throws IOException { - LOG.info("--- START: testAppRunningKill ---"); + testAppRunningKillInternal("TestKillAppReason"); + reset(writer, store); + testAppRunningKillInternal(null); + } + private void testAppRunningKillInternal(String reason) throws IOException { + LOG.info("--- START: testAppRunningKill " + reason + " ---"); RMApp application = testCreateAppRunning(null); // RUNNING => KILLED event RMAppEventType.KILL - RMAppEvent event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + RMAppEvent event = + new RMAppKillEvent(application.getApplicationId(), reason); application.handle(event); rmDispatcher.await(); @@ -671,8 +694,8 @@ public void testAppRunningKill() throws IOException { assertAppState(RMAppState.KILLING, application); sendAttemptUpdateSavedEvent(application); sendAppUpdateSavedEvent(application); - assertKilled(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertKilled(application, reason); + verify(writer).applicationFinished(eq(application)); } @Test @@ -719,15 +742,15 @@ public void testAppRunningFailed() throws IOException { rmDispatcher.await(); sendAppUpdateSavedEvent(application); assertFailed(application, ".*Failing the application.*"); - assertAppFinalStateSaved(application); + assertAppFinalStateSaved(); // FAILED => FAILED event RMAppEventType.KILL - event = new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + event = new RMAppKillEvent(application.getApplicationId()); application.handle(event); rmDispatcher.await(); assertFailed(application, ".*Failing the application.*"); - assertAppFinalStateSaved(application); - verify(writer).applicationFinished(any(RMApp.class)); + assertAppFinalStateSaved(); + verify(writer).applicationFinished(eq(application)); } @Test @@ -736,8 +759,7 @@ public void testAppAtFinishingIgnoreKill() throws IOException { RMApp application = testCreateAppFinishing(null); // FINISHING => FINISHED event RMAppEventType.KILL - RMAppEvent event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + RMAppEvent event = new RMAppKillEvent(application.getApplicationId()); application.handle(event); rmDispatcher.await(); assertAppState(RMAppState.FINISHING, application); @@ -776,8 +798,8 @@ public void testAppFinishedFinished() throws IOException { RMApp application = testCreateAppFinished(null, ""); // FINISHED => FINISHED event RMAppEventType.KILL - RMAppEvent event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + RMAppEvent event = new RMAppKillEvent(application.getApplicationId(), + "TestAppKillReason"); application.handle(event); rmDispatcher.await(); assertTimesAtFinish(application); @@ -785,7 +807,7 @@ public void testAppFinishedFinished() throws IOException { StringBuilder diag = application.getDiagnostics(); Assert.assertEquals("application diagnostics is not correct", "", diag.toString()); - verify(writer).applicationFinished(any(RMApp.class)); + verify(writer).applicationFinished(eq(application)); } @Test (timeout = 30000) @@ -804,8 +826,7 @@ public void testAppFailedFailed() throws IOException { assertAppState(RMAppState.FAILED, application); // FAILED => FAILED event RMAppEventType.KILL - event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + event = new RMAppKillEvent(application.getApplicationId()); application.handle(event); rmDispatcher.await(); assertTimesAtFinish(application); @@ -813,7 +834,7 @@ public void testAppFailedFailed() throws IOException { assertTimesAtFinish(application); assertAppState(RMAppState.FAILED, application); - verify(writer).applicationFinished(any(RMApp.class)); + verify(writer).applicationFinished(eq(application)); } @Test (timeout = 30000) @@ -823,8 +844,7 @@ public void testAppKilledKilled() throws IOException { RMApp application = testCreateAppRunning(null); // RUNNING => KILLED event RMAppEventType.KILL - RMAppEvent event = - new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + RMAppEvent event = new RMAppKillEvent(application.getApplicationId()); application.handle(event); rmDispatcher.await(); sendAttemptUpdateSavedEvent(application); @@ -851,7 +871,7 @@ public void testAppKilledKilled() throws IOException { // KILLED => KILLED event RMAppEventType.KILL - event = new RMAppEvent(application.getApplicationId(), RMAppEventType.KILL); + event = new RMAppKillEvent(application.getApplicationId()); application.handle(event); rmDispatcher.await(); assertTimesAtFinish(application); @@ -859,7 +879,7 @@ public void testAppKilledKilled() throws IOException { assertTimesAtFinish(application); assertAppState(RMAppState.KILLED, application); - verify(writer).applicationFinished(any(RMApp.class)); + verify(writer).applicationFinished(eq(application)); } @Test