diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/RegisterNodeManagerResponse.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/RegisterNodeManagerResponse.java index 1c1a9dd..26e2c8a 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/RegisterNodeManagerResponse.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/RegisterNodeManagerResponse.java @@ -30,4 +30,7 @@ void setNodeAction(NodeAction nodeAction); + long getClusterTimestamp(); + + void setClusterTimestamp(long clusterTimestamp); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/impl/pb/RegisterNodeManagerResponsePBImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/impl/pb/RegisterNodeManagerResponsePBImpl.java index c28d4c9..f008f1f 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/impl/pb/RegisterNodeManagerResponsePBImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/protocolrecords/impl/pb/RegisterNodeManagerResponsePBImpl.java @@ -121,6 +121,18 @@ public void setNodeAction(NodeAction nodeAction) { rebuild = true; } + @Override + public long getClusterTimestamp() { + RegisterNodeManagerResponseProtoOrBuilder p = viaProto ? proto : builder; + return (p.getClusterTimestamp()); + } + + @Override + public void setClusterTimestamp(long clusterTimestamp) { + maybeInitBuilder(); + builder.setClusterTimestamp(clusterTimestamp); + } + private NodeAction convertFromProtoFormat(NodeActionProto p) { return NodeAction.valueOf(p.name()); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/proto/yarn_server_common_service_protos.proto hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/proto/yarn_server_common_service_protos.proto index 931dccd..5834240 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/proto/yarn_server_common_service_protos.proto +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/proto/yarn_server_common_service_protos.proto @@ -33,6 +33,7 @@ message RegisterNodeManagerRequestProto { message RegisterNodeManagerResponseProto { optional MasterKeyProto master_key = 1; optional NodeActionProto nodeAction = 2; + optional int64 cluster_timestamp = 3; } message NodeHeartbeatRequestProto { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java index a5d16c5..03f68f2 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeManager.java @@ -226,8 +226,12 @@ protected void cleanupContainersOnResync() { new Thread() { @Override public void run() { + containerManager.setBlockContainerRequest(true); + LOG.info("Notify container manager to block container request while resyncing"); cleanupContainers(NodeManagerEventType.RESYNC); ((NodeStatusUpdaterImpl) nodeStatusUpdater ).rebootNodeStatusUpdater(); + LOG.info("Notify container manager to reset blockContainerRequest"); + containerManager.setBlockContainerRequest(false); } }.start(); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdater.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdater.java index 41949e7..8c6a4ce 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdater.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdater.java @@ -25,4 +25,5 @@ void sendOutofBandHeartBeat(); NodeStatus getNodeStatusAndUpdateContainersInContext(); + long getNMRegistrationTime(); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java index e9583c2..f76efa7 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/NodeStatusUpdaterImpl.java @@ -95,6 +95,8 @@ private Runnable statusUpdaterRunnable; private Thread statusUpdater; + // Initialize as -1 to avoid modifying other test cases + private long registrationTime = -1; public NodeStatusUpdaterImpl(Context context, Dispatcher dispatcher, NodeHealthCheckerService healthChecker, NodeManagerMetrics metrics) { @@ -267,6 +269,7 @@ protected void registerWithRM() throws YarnRemoteException { this.resourceTracker = getRMClient(); regNMResponse = this.resourceTracker.registerNodeManager(request); + this.registrationTime = regNMResponse.getClusterTimestamp(); break; } catch(Throwable e) { LOG.warn("Trying to connect to ResourceManager, " + @@ -334,6 +337,7 @@ protected void registerWithRM() throws YarnRemoteException { return appList; } + @Override public NodeStatus getNodeStatusAndUpdateContainersInContext() { NodeStatus nodeStatus = recordFactory.newRecordInstance(NodeStatus.class); @@ -407,6 +411,11 @@ public void sendOutofBandHeartBeat() { } } + @Override + public long getNMRegistrationTime() { + return registrationTime; + } + protected void startStatusUpdater() { statusUpdaterRunnable = new Runnable() { diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java index 8fc8a3e..2f830ee 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/ContainerManagerImpl.java @@ -125,6 +125,7 @@ private final ApplicationACLsManager aclsManager; private final DeletionService deletionService; + private boolean blockContainerRequest = false; public ContainerManagerImpl(Context context, ContainerExecutor exec, DeletionService deletionContext, NodeStatusUpdater nodeStatusUpdater, @@ -393,6 +394,12 @@ private void authorizeRequest(String containerIDStr, @Override public StartContainerResponse startContainer(StartContainerRequest request) throws YarnRemoteException { + + if (blockContainerRequest) { + throw RPCUtil + .getRemoteException("Block container request because NM is resyncing"); + } + ContainerLaunchContext launchContext = request.getContainerLaunchContext(); org.apache.hadoop.yarn.api.records.Container lauchContainer = request.getContainer(); @@ -402,6 +409,17 @@ public StartContainerResponse startContainer(StartContainerRequest request) UserGroupInformation remoteUgi = getRemoteUgi(containerIDStr); authorizeRequest(containerIDStr, launchContext, lauchContainer, remoteUgi); + // Is the container coming from previous RM + long containerRequestTimestamp = + containerID.getApplicationAttemptId().getApplicationId() + .getClusterTimestamp(); + if (containerRequestTimestamp < nodeStatusUpdater.getNMRegistrationTime()) { + String msg = "\n Invalid container request " + containerIDStr + + " from previous RM " + nodeStatusUpdater.getNMRegistrationTime(); + LOG.error(msg); + throw RPCUtil.getRemoteException(msg); + } + LOG.info("Start request for " + containerIDStr + " by user " + launchContext.getUser()); @@ -615,6 +633,14 @@ public void handle(ContainerManagerEvent event) { } } + public void setBlockContainerRequest(boolean blockContainerRequest) { + this.blockContainerRequest = blockContainerRequest; + } + + public boolean getBlockContainerRequest() { + return this.blockContainerRequest; + } + @Override public void stateChanged(Service service) { // TODO Auto-generated method stub diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerManagerWithLCE.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerManagerWithLCE.java index 44328db..a23f125 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerManagerWithLCE.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestContainerManagerWithLCE.java @@ -142,6 +142,17 @@ public void testLocalFilesCleanup() throws InterruptedException, super.testLocalFilesCleanup(); } + @Override + public void testContainerLaunchFromPreviousRM() throws InterruptedException, + IOException { + // Don't run the test if the binary is not available. + if (!shouldRunTest()) { + LOG.info("LCE binary path is not passed. Not running the test"); + return; + } + LOG.info("Running testContainerLaunchFromPreviousRM"); + super.testContainerLaunchFromPreviousRM(); + } private boolean shouldRunTest() { return System .getProperty(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH) != null; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestNodeManagerShutdown.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestNodeManagerShutdown.java index 1efe80d..b87c8ee 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestNodeManagerShutdown.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestNodeManagerShutdown.java @@ -82,7 +82,7 @@ static final String user = "nobody"; private FileContext localFS; private CyclicBarrier syncBarrier = new CyclicBarrier(2); - + private boolean skipLaunchContainersThread = false; @Before public void setup() throws UnsupportedFileSystemException { localFS = FileContext.getLocalFSFileContext(); @@ -95,6 +95,7 @@ public void setup() throws UnsupportedFileSystemException { @After public void tearDown() throws IOException, InterruptedException { localFS.delete(new Path(basedir.getPath()), true); + syncBarrier.reset(); } @Test @@ -153,6 +154,28 @@ public void testKillContainersOnResync() throws IOException, InterruptedExceptio } catch (BrokenBarrierException e) { } assert ((TestNodeManager) nm).getNMRegistrationCount() == 2; + nm.stop(); + } + + @SuppressWarnings("unchecked") + @Test + public void testBlockContainerRequestOnResync() throws IOException, + InterruptedException { + NodeManager nm = new TestNodeManager2(); + YarnConfiguration conf = createNMConfig(); + nm.init(conf); + nm.start(); + startContainers(nm); + + nm.getNMDispatcher().getEventHandler() + .handle(new NodeManagerEvent(NodeManagerEventType.RESYNC)); + try { + syncBarrier.await(); + } catch (BrokenBarrierException e) { + } + //In normal stop, skip launching test thread + skipLaunchContainersThread = true; + nm.stop(); } private void startContainers(NodeManager nm) throws IOException { @@ -304,4 +327,97 @@ protected void rebootNodeStatusUpdater() { } } } + + class TestNodeManager2 extends NodeManager { + + Thread launchContainersThread = null; + @Override + protected NodeStatusUpdater createNodeStatusUpdater(Context context, + Dispatcher dispatcher, NodeHealthCheckerService healthChecker) { + return new TestNodeStatusUpdaterImpl(context, dispatcher, + healthChecker, metrics); + } + + @Override + public void cleanupContainers(NodeManagerEventType eventType) { + + // Create a thread keeping launching containers while resyncing + launchContainersThread = new Thread() { + @Override + public void run() { + int numContainers = 0; + int numContainersRejected = 0; + ContainerLaunchContext containerLaunchContext = + recordFactory.newRecordInstance(ContainerLaunchContext.class); + + while (numContainers++ < 10) { + ContainerId cId = createContainerId(System.currentTimeMillis()); + Container container = + BuilderUtils.newContainer(cId, null, null, null, null, null); + StartContainerRequest startRequest = + recordFactory.newRecordInstance(StartContainerRequest.class); + startRequest.setContainerLaunchContext(containerLaunchContext); + startRequest.setContainer(container); + System.out.println("no. of containers to be launched: " + + numContainers); + try { + getContainerManager().startContainer(startRequest); + } catch (YarnRemoteException e) { + numContainersRejected++; + } + } + // no. of containers to be launched should equal to no. of + // containers rejected + Assert.assertEquals(numContainers - 1, numContainersRejected); + } + }; + if (!skipLaunchContainersThread) { + launchContainersThread.start(); + } + try { + super.cleanupContainers(eventType); + } catch (Exception e) { + } + } + + class TestNodeStatusUpdaterImpl extends MockNodeStatusUpdater { + + public TestNodeStatusUpdaterImpl(Context context, Dispatcher dispatcher, + NodeHealthCheckerService healthChecker, NodeManagerMetrics metrics) { + super(context, dispatcher, healthChecker, metrics); + } + + @Override + protected void rebootNodeStatusUpdater() { + ConcurrentMap containers = + getNMContext().getContainers(); + // ensure that containers are empty before restart nodeStatusUpdater + Assert.assertTrue(containers.isEmpty()); + super.rebootNodeStatusUpdater(); + + // After this point new containers are free to be launched, except + // containers from previous RM + try { + launchContainersThread.join(); + syncBarrier.await(); + } catch (InterruptedException e) { + } catch (BrokenBarrierException e) { + } + } + } + } + + private ContainerId createContainerId(long timeStamp) { + ApplicationId appId = recordFactory.newRecordInstance(ApplicationId.class); + appId.setClusterTimestamp(timeStamp); + appId.setId(0); + ApplicationAttemptId appAttemptId = + recordFactory.newRecordInstance(ApplicationAttemptId.class); + appAttemptId.setApplicationId(appId); + appAttemptId.setAttemptId(1); + ContainerId containerId = + recordFactory.newRecordInstance(ContainerId.class); + containerId.setApplicationAttemptId(appAttemptId); + return containerId; + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestContainerManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestContainerManager.java index d405a7c..f6563ae 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestContainerManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestContainerManager.java @@ -18,6 +18,9 @@ package org.apache.hadoop.yarn.server.nodemanager.containermanager; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -48,6 +51,7 @@ import org.apache.hadoop.yarn.api.records.LocalResource; import org.apache.hadoop.yarn.api.records.LocalResourceType; import org.apache.hadoop.yarn.api.records.LocalResourceVisibility; +import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.api.records.URL; import org.apache.hadoop.yarn.exceptions.YarnRemoteException; import org.apache.hadoop.yarn.server.nodemanager.CMgrCompletedAppsEvent; @@ -61,7 +65,6 @@ import org.apache.hadoop.yarn.util.BuilderUtils; import org.apache.hadoop.yarn.util.ConverterUtils; import org.junit.Test; -import static org.mockito.Mockito.*; public class TestContainerManager extends BaseContainerManagerTest { @@ -73,9 +76,9 @@ public TestContainerManager() throws UnsupportedFileSystemException { LOG = LogFactory.getLog(TestContainerManager.class); } - private ContainerId createContainerId() { + private ContainerId createContainerId(long timeStamp) { ApplicationId appId = recordFactory.newRecordInstance(ApplicationId.class); - appId.setClusterTimestamp(0); + appId.setClusterTimestamp(timeStamp); appId.setId(0); ApplicationAttemptId appAttemptId = recordFactory.newRecordInstance(ApplicationAttemptId.class); @@ -97,7 +100,7 @@ public void testContainerManagerInitialization() throws IOException { try { GetContainerStatusRequest request = recordFactory.newRecordInstance(GetContainerStatusRequest.class); - ContainerId cId = createContainerId(); + ContainerId cId = createContainerId(0); request.setContainerId(cId); containerManager.getContainerStatus(request); } catch (YarnRemoteException e) { @@ -122,7 +125,7 @@ public void testContainerSetup() throws IOException, InterruptedException { ContainerLaunchContext container = recordFactory.newRecordInstance(ContainerLaunchContext.class); // ////// Construct the Container-id - ContainerId cId = createContainerId(); + ContainerId cId = createContainerId(0); container.setUser(user); @@ -210,7 +213,7 @@ public void testContainerLaunchAndStop() throws IOException, recordFactory.newRecordInstance(ContainerLaunchContext.class); // ////// Construct the Container-id - ContainerId cId = createContainerId(); + ContainerId cId = createContainerId(0); containerLaunchContext.setUser(user); @@ -313,7 +316,7 @@ private void testContainerLaunchAndExit(int exitCode) throws IOException, Interr recordFactory.newRecordInstance(ContainerLaunchContext.class); // ////// Construct the Container-id - ContainerId cId = createContainerId(); + ContainerId cId = createContainerId(0); containerLaunchContext.setUser(user); @@ -405,7 +408,7 @@ public void testLocalFilesCleanup() throws InterruptedException, ContainerLaunchContext container = recordFactory.newRecordInstance(ContainerLaunchContext.class); // ////// Construct the Container-id - ContainerId cId = createContainerId(); + ContainerId cId = createContainerId(0); ApplicationId appId = cId.getApplicationAttemptId().getApplicationId(); container.setUser(user); @@ -500,4 +503,54 @@ public void testLocalFilesCleanup() throws InterruptedException, Assert.assertFalse(targetFile.getAbsolutePath() + " exists!!", targetFile.exists()); } + + @Test + public void testContainerLaunchFromPreviousRM() throws IOException, + InterruptedException { + containerManager.start(); + ContainerLaunchContext containerLaunchContext = + recordFactory.newRecordInstance(ContainerLaunchContext.class); + + // Construct the Container-id with a timestamp from previous RM, its + // negative because NMRegistrationTimeStamp is initialized as -1 by default + ContainerId cId1 = createContainerId(-2); + // Construct the Container-id with a timestamp within current RM + ContainerId cId2 = createContainerId(System.currentTimeMillis()); + containerLaunchContext.setUser(user); + containerLaunchContext + .setLocalResources(new HashMap()); + containerLaunchContext.setUser(containerLaunchContext.getUser()); + Resource mockResource = mock(Resource.class); + + Container container1 = + BuilderUtils.newContainer(cId1, null, null, mockResource, null, null); + StartContainerRequest startRequest1 = + recordFactory.newRecordInstance(StartContainerRequest.class); + startRequest1.setContainerLaunchContext(containerLaunchContext); + startRequest1.setContainer(container1); + boolean catchException = false; + try { + containerManager.startContainer(startRequest1); + } catch (YarnRemoteException e) { + catchException = true; + } + + // Verify that startContainer fail because of invalid container request + Assert.assertTrue(catchException); + + Container container2 = + BuilderUtils.newContainer(cId2, null, null, mockResource, null, null); + StartContainerRequest startRequest2 = + recordFactory.newRecordInstance(StartContainerRequest.class); + startRequest2.setContainerLaunchContext(containerLaunchContext); + startRequest2.setContainer(container2); + boolean noException = true; + try { + containerManager.startContainer(startRequest2); + } catch (YarnRemoteException e) { + noException = false; + } + // Verify that startContainer get no YarnRemoteException + Assert.assertTrue(noException); + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java index 4cd1969..986c8a7 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceManager.java @@ -125,6 +125,7 @@ protected RMContext rmContext; protected ResourceTrackerService resourceTracker; private boolean recoveryEnabled; + private static long startTimestamp; private Configuration conf; @@ -748,10 +749,15 @@ public void recover(RMState state) throws Exception { // recover applications rmAppManager.recover(state); } + + public static long getStartTimestamp() { + return startTimestamp; + } public static void main(String argv[]) { Thread.setDefaultUncaughtExceptionHandler(new YarnUncaughtExceptionHandler()); StringUtils.startupShutdownMessage(ResourceManager.class, argv, LOG); + startTimestamp = System.currentTimeMillis(); try { Configuration conf = new YarnConfiguration(); ResourceManager resourceManager = new ResourceManager(); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java index 258c7dc..cefa2ee 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ResourceTrackerService.java @@ -196,6 +196,7 @@ public RegisterNodeManagerResponse registerNodeManager( + capability + ", assigned nodeId " + nodeId); response.setNodeAction(NodeAction.NORMAL); + response.setClusterTimestamp(ResourceManager.getStartTimestamp()); return response; }