diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java index c31f4ed..e896c78 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/RMAppAttemptImpl.java @@ -734,9 +734,9 @@ public void transition(RMAppAttemptImpl appAttempt, .registerAppAttempt(appAttempt.applicationAttemptId); if (UserGroupInformation.isSecurityEnabled()) { - appAttempt.clientTokenMasterKey = appAttempt.rmContext - .getClientToAMTokenSecretManager() - .registerApplication(appAttempt.applicationAttemptId); + appAttempt.clientTokenMasterKey = + appAttempt.rmContext.getClientToAMTokenSecretManager() + .createMasterKey(appAttempt.applicationAttemptId); } // create AMRMToken @@ -922,6 +922,12 @@ public void transition(RMAppAttemptImpl appAttempt, RMAppAttemptEvent event) { // Register with AMLivelinessMonitor appAttempt.attemptLaunched(); + + // register the ClientTokenMasterKey after it is saved in the store, + // otherwise client may hold an invalid ClientToken after RM restarts. + appAttempt.rmContext.getClientToAMTokenSecretManager() + .registerApplication(appAttempt.getAppAttemptId(), + appAttempt.getClientTokenMasterKey()); } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ClientToAMTokenSecretManagerInRM.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ClientToAMTokenSecretManagerInRM.java index b5efa9f..4fbe2ce 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ClientToAMTokenSecretManagerInRM.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ClientToAMTokenSecretManagerInRM.java @@ -33,17 +33,21 @@ private Map masterKeys = new HashMap(); - public synchronized SecretKey registerApplication( + public synchronized SecretKey createMasterKey( ApplicationAttemptId applicationAttemptID) { - SecretKey key = generateSecret(); + return generateSecret(); + } + + public synchronized void registerApplication( + ApplicationAttemptId applicationAttemptID, SecretKey key) { this.masterKeys.put(applicationAttemptID, key); - return key; } + // Only for RM recovery public synchronized SecretKey registerMasterKey( ApplicationAttemptId applicationAttemptID, byte[] keyData) { SecretKey key = createSecretKey(keyData); - this.masterKeys.put(applicationAttemptID, key); + registerApplication(applicationAttemptID, key); return key; } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java index aef92d5..6b4b062 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/recovery/TestRMStateStore.java @@ -239,7 +239,7 @@ void testRMAppStateStore(RMStateStoreHelper stateStoreHelper) throws Exception { HashSet> attemptTokenSet1 = new HashSet>(); attemptTokenSet1.add(appAttemptToken1); SecretKey clientTokenKey1 = - clientToAMTokenMgr.registerApplication(attemptId1); + clientToAMTokenMgr.createMasterKey(attemptId1); ContainerId containerId1 = storeAttempt(store, attemptId1, "container_1352994193343_0001_01_000001", @@ -255,7 +255,7 @@ void testRMAppStateStore(RMStateStoreHelper stateStoreHelper) throws Exception { HashSet> attemptTokenSet2 = new HashSet>(); attemptTokenSet2.add(appAttemptToken2); SecretKey clientTokenKey2 = - clientToAMTokenMgr.registerApplication(attemptId2); + clientToAMTokenMgr.createMasterKey(attemptId2); ContainerId containerId2 = storeAttempt(store, attemptId2, "container_1352994193343_0001_02_000001", diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java 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 7f03e1d..fdc145c 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppTransitions.java @@ -18,13 +18,18 @@ package org.apache.hadoop.yarn.server.resourcemanager.rmapp; -import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.List; import junit.framework.Assert; @@ -35,10 +40,13 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; import org.apache.hadoop.yarn.MockApps; +import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationReport; import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext; +import org.apache.hadoop.yarn.api.records.Container; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; +import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.api.records.impl.pb.ApplicationSubmissionContextPBImpl; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.event.DrainDispatcher; @@ -54,7 +62,10 @@ 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.RMAppAttemptContainerAllocatedEvent; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.event.RMAppAttemptStoredEvent; import org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.ContainerAllocationExpirer; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.Allocation; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.SchedulerEvent; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.SchedulerEventType; @@ -62,7 +73,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.security.ClientToAMTokenSecretManagerInRM; import org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM; import org.apache.hadoop.yarn.server.resourcemanager.security.RMContainerTokenSecretManager; -import org.junit.After; +import org.apache.hadoop.yarn.server.utils.BuilderUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -81,6 +92,7 @@ private static int appId = 1; private DrainDispatcher rmDispatcher; private RMStateStore store; + private YarnScheduler scheduler; // ignore all the RM application attempt events private static final class TestApplicationAttemptEventDispatcher implements @@ -206,7 +218,8 @@ protected RMApp createNewTestApp(ApplicationSubmissionContext submissionContext) String queue = MockApps.newQueue(); // ensure max application attempts set to known value conf.setInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, maxAppAttempts); - YarnScheduler scheduler = mock(YarnScheduler.class); + scheduler = mock(YarnScheduler.class); + ApplicationMasterService masterService = new ApplicationMasterService(rmContext, scheduler); @@ -818,6 +831,7 @@ public void testClientTokens() throws Exception { assertAppState(RMAppState.RUNNING, app); report = app.createAndGetApplicationReport(null, true); Assert.assertNull(report.getClientToAMToken()); + moveCurrentAttemptToLaunchedState(app.getCurrentAppAttempt()); report = app.createAndGetApplicationReport("clientuser", true); Assert.assertNotNull(report.getClientToAMToken()); @@ -830,4 +844,32 @@ public void testClientTokens() throws Exception { report = app.createAndGetApplicationReport("clientuser", true); Assert.assertNull(report.getClientToAMToken()); } + + private void moveCurrentAttemptToLaunchedState(RMAppAttempt attempt) { + attempt.handle(new RMAppAttemptEvent(attempt.getAppAttemptId(), + RMAppAttemptEventType.APP_ACCEPTED)); + // Mock the allocation of AM container + Container container = mock(Container.class); + Resource resource = BuilderUtils.newResource(2048, 1); + when(container.getId()).thenReturn( + BuilderUtils.newContainerId(attempt.getAppAttemptId(), 1)); + when(container.getResource()).thenReturn(resource); + Allocation allocation = mock(Allocation.class); + when(allocation.getContainers()).thenReturn( + Collections.singletonList(container)); + when(allocation.getContainers()). + thenReturn(Collections.singletonList(container)); + when( + scheduler.allocate(any(ApplicationAttemptId.class), any(List.class), + any(List.class), any(List.class), any(List.class))).thenReturn( + allocation); + attempt.handle(new RMAppAttemptContainerAllocatedEvent(attempt + .getAppAttemptId(), container)); + attempt + .handle(new RMAppAttemptStoredEvent(attempt.getAppAttemptId(), null)); + attempt.handle(new RMAppAttemptEvent(attempt.getAppAttemptId(), + RMAppAttemptEventType.LAUNCHED)); + + assertEquals(RMAppAttemptState.LAUNCHED, attempt.getAppAttemptState()); + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/TestRMAppAttemptTransitions.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/TestRMAppAttemptTransitions.java index 39c6337..037b7df 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/TestRMAppAttemptTransitions.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/attempt/TestRMAppAttemptTransitions.java @@ -35,6 +35,8 @@ import java.util.Collections; import java.util.List; +import junit.framework.Assert; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -294,9 +296,8 @@ private void testAppAttemptSubmittedState() { assertEquals(0, applicationAttempt.getRanNodes().size()); assertNull(applicationAttempt.getFinalApplicationStatus()); if (UserGroupInformation.isSecurityEnabled()) { - verify(clientToAMTokenManager).registerApplication( + verify(clientToAMTokenManager).createMasterKey( applicationAttempt.getAppAttemptId()); - assertNotNull(applicationAttempt.createClientToken("some client")); } assertNull(applicationAttempt.createClientToken(null)); assertNotNull(applicationAttempt.getAMRMToken()); @@ -428,7 +429,10 @@ private void testAppAttemptLaunchedState(Container container) { assertEquals(RMAppAttemptState.LAUNCHED, applicationAttempt.getAppAttemptState()); assertEquals(container, applicationAttempt.getMasterContainer()); - + if (UserGroupInformation.isSecurityEnabled()) { + Assert.assertNotNull(clientToAMTokenManager + .getMasterKey(applicationAttempt.getAppAttemptId())); + } // TODO - need to add more checks relevant to this state } @@ -561,6 +565,11 @@ private Container allocateApplicationAttempt() { } private void launchApplicationAttempt(Container container) { + if (UserGroupInformation.isSecurityEnabled()) { + // before LAUNCHED state, ClientTokenMasterKey doesn't exist. + Assert.assertNull(clientToAMTokenManager.getMasterKey(applicationAttempt + .getAppAttemptId())); + } applicationAttempt.handle( new RMAppAttemptEvent(applicationAttempt.getAppAttemptId(), RMAppAttemptEventType.LAUNCHED)); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java index 97a3c26..0830f11 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientToAMTokens.java @@ -194,16 +194,6 @@ protected void doSecureLogin() throws IOException { nm1.nodeHeartbeat(true); dispatcher.await(); - // Get the app-report. - GetApplicationReportRequest request = - Records.newRecord(GetApplicationReportRequest.class); - request.setApplicationId(app.getApplicationId()); - GetApplicationReportResponse reportResponse = - rm.getClientRMService().getApplicationReport(request); - ApplicationReport appReport = reportResponse.getApplicationReport(); - org.apache.hadoop.yarn.api.records.Token originalClientToAMToken = - appReport.getClientToAMToken(); - ApplicationAttemptId appAttempt = app.getCurrentAppAttempt().getAppAttemptId(); final MockAM mockAM = new MockAM(rm.getRMContext(), rm.getApplicationMasterService(), @@ -224,7 +214,17 @@ public RegisterApplicationMasterResponse run() { return response; } }); - + + // Get the app-report. + GetApplicationReportRequest request = + Records.newRecord(GetApplicationReportRequest.class); + request.setApplicationId(app.getApplicationId()); + GetApplicationReportResponse reportResponse = + rm.getClientRMService().getApplicationReport(request); + ApplicationReport appReport = reportResponse.getApplicationReport(); + org.apache.hadoop.yarn.api.records.Token originalClientToAMToken = + appReport.getClientToAMToken(); + // ClientToAMToken master key should have been received on register // application master response. Assert.assertNotNull(response.getClientToAMTokenMasterKey());