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..86aabde 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,11 @@ private void clearUnusedFields() { this.submissionContext.setAMContainerSpec(null); this.submissionContext.setLogAggregationContext(null); } + /** + * catch the InvalidStateTransition for unit test + * @param oldState + * @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..d901f70 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 @@ -38,7 +38,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -129,6 +131,28 @@ private YarnScheduler scheduler; private TestSchedulerEventDispatcher schedulerDispatcher; + //for catching InvalidStateTransition + private static 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); + } + + } // ignore all the RM application attempt events private static final class TestApplicationAttemptEventDispatcher implements EventHandler { @@ -394,7 +418,7 @@ protected RMApp createNewTestApp(ApplicationSubmissionContext submissionContext.setAMContainerSpec(prepareContainerLaunchContext()); submissionContext.setLogAggregationContext(getLogAggregationContext()); - RMApp application = new RMAppImpl(applicationId, rmContext, conf, name, + RMApp application = new RMAppImplForTest(applicationId, rmContext, conf, name, user, queue, submissionContext, scheduler, masterService, System.currentTimeMillis(), "YARN", null, new ArrayList()); @@ -1151,6 +1175,34 @@ public void testAppKilledKilled() throws IOException { verifyRMAppFieldsForFinalTransitions(application); } + @Test (timeout = 30000) + public void testStartAfterKilled() throws IOException { + LOG.info("--- START: testStartAfterKilled ---"); + + UserGroupInformation fooUser = UserGroupInformation.createUserForTesting( + "fooTestStartAfterKilled", new String[] {"foo_group"}); + + RMApp application = createNewTestApp(null); + // NEW => KILLED event RMAppEventType.KILL + RMAppEvent event = new RMAppKillByClientEvent( + application.getApplicationId(), "Application killed by user.", fooUser, + Server.getRemoteIp()); + application.handle(event); + rmDispatcher.await(); + assertTimesAtFinish(application); + assertAppState(RMAppState.KILLED, application); + verifyApplicationFinished(RMAppState.KILLED); + + // KILLED => KILLED event RMAppEventType.START + event = + new RMAppFailedAttemptEvent(application.getApplicationId(), + RMAppEventType.START, "", false); + application.handle(event); + rmDispatcher.await(); + assertTimesAtFinish(application); + assertAppState(RMAppState.KILLED, application); + } + @Test(timeout = 30000) public void testAppsRecoveringStates() throws Exception { RMState state = new RMState();