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 38f666b..a7e55c2 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 @@ -400,7 +400,7 @@ EnumSet.of(RMAppEventType.APP_ACCEPTED, RMAppEventType.APP_REJECTED, RMAppEventType.KILL, RMAppEventType.ATTEMPT_FINISHED, RMAppEventType.ATTEMPT_FAILED, - RMAppEventType.NODE_UPDATE)) + RMAppEventType.NODE_UPDATE, RMAppEventType.START)) .installTopology(); @@ -885,6 +885,7 @@ public void handle(RMAppEvent event) { } catch (InvalidStateTransitionException e) { LOG.error("App: " + appID + " can't handle this event at current state", e); + onInvalidStateTransition(event.getType(), oldState); /* TODO fail the application on the failed transition */ } @@ -2035,4 +2036,12 @@ private void clearUnusedFields() { this.submissionContext.setAMContainerSpec(null); this.submissionContext.setLogAggregationContext(null); } + + /** + * catch the InvalidStateTransition for unit test + * @param state + * @param rmAppEventType + */ + protected void onInvalidStateTransition(RMAppEventType rmAppEventType, + RMAppState state){} } 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 344f8bb7..7b83305 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 @@ -39,6 +39,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.List; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -1151,6 +1153,70 @@ public void testAppKilledKilled() throws IOException { verifyRMAppFieldsForFinalTransitions(application); } + @Test (timeout = 30000) + public void testAppStartAfterKilled() throws Exception { + LOG.info("--- START: testStartAfterKilled ---"); + //for catching InvalidStateTransition + final class RMAppImplForTest extends RMAppImpl { + + public RMAppImplForTest(ApplicationId applicationId, RMContext rmContext, + Configuration config, String name,String user, String queue, + ApplicationSubmissionContext submissionContext,YarnScheduler scheduler, + ApplicationMasterService masterService, long submitTime, + String applicationType,Set applicationTags, + List amReqs) { + super(applicationId, rmContext, config, name, user, queue, + submissionContext, scheduler, masterService,submitTime, + applicationType, applicationTags, amReqs); + } + + @Override + protected void onInvalidStateTransition(RMAppEventType rmAppEventType, + RMAppState state) { + Assert.assertTrue("RMAppImpl: can't handle " + rmAppEventType + + " at state " + state, false); + } + } + //create a new application + + RMApp application = createNewTestApp(null); + ApplicationMasterService masterService = + new ApplicationMasterService(rmContext, scheduler); + RMApp applicationForTest = new RMAppImplForTest(application.getApplicationId(), + rmContext, conf,application.getName(), + application.getUser(), application.getQueue(), + application.getApplicationSubmissionContext(), + scheduler, masterService,application.getSubmitTime(), + "YARN", null,new ArrayList()); + application = applicationForTest; + this.rmContext.getRMApps().put(application.getApplicationId(), + application); + + UserGroupInformation fooUser = UserGroupInformation.createUserForTesting( + "fooTestAppNewKill", new String[] {"foo_group"}); + // NEW => KILLED event RMAppEventType.KILL + RMAppEvent event = new RMAppKillByClientEvent( + applicationForTest.getApplicationId(), "Application killed by user.", + fooUser,Server.getRemoteIp()); + application.handle(event); + rmDispatcher.await(); + assertKilled(application); + + // KILLED => KILLED event RMAppEventType.START + event = + new RMAppFailedAttemptEvent(application.getApplicationId(), + RMAppEventType.START, "", false); + application.handle(event); + rmDispatcher.await(); + assertTimesAtFinish(application); + assertAppState(RMAppState.KILLED, application); + + assertAppFinalStateNotSaved(application); + verifyApplicationFinished(RMAppState.KILLED); + verifyAppRemovedSchedulerEvent(RMAppState.KILLED); + verifyRMAppFieldsForFinalTransitions(application); + } + @Test(timeout = 30000) public void testAppsRecoveringStates() throws Exception { RMState state = new RMState();