diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java index 7dac2cd6e68..3d1ba24ecac 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ApplicationMasterService.java @@ -61,6 +61,8 @@ import org.apache.hadoop.yarn.security.AMRMTokenIdentifier; 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.RMAppImpl; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.AMLivelinessMonitor; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; @@ -75,6 +77,8 @@ import org.apache.hadoop.yarn.server.resourcemanager.security.authorize.RMPolicyProvider; import org.apache.hadoop.yarn.server.security.MasterKeyData; import org.apache.hadoop.yarn.server.utils.YarnServerSecurityUtils; +import org.apache.hadoop.yarn.util.Clock; +import org.apache.hadoop.yarn.util.MonotonicClock; import org.apache.hadoop.yarn.util.resource.Resources; import com.google.common.annotations.VisibleForTesting; @@ -86,6 +90,11 @@ private static final Log LOG = LogFactory.getLog(ApplicationMasterService.class); private static final int PRE_REGISTER_RESPONSE_ID = -1; + private Clock clock; + + private static final String MAXIMUM_LIFETIME_KEY = + YarnConfiguration.RM_PREFIX + "application.maximum-lifetime-seconds"; + private final AMLivelinessMonitor amLivelinessMonitor; private YarnScheduler rScheduler; protected InetSocketAddress masterServiceAddress; @@ -96,6 +105,7 @@ new ConcurrentHashMap(); protected final RMContext rmContext; private final AMSProcessingChain amsProcessingChain; + private boolean appMaxTimeEnabled; public ApplicationMasterService(RMContext rmContext, YarnScheduler scheduler) { @@ -109,6 +119,7 @@ public ApplicationMasterService(String name, RMContext rmContext, this.rScheduler = scheduler; this.rmContext = rmContext; this.amsProcessingChain = new AMSProcessingChain(new DefaultAMSProcessor()); + this.clock = new MonotonicClock(); } @Override @@ -119,6 +130,13 @@ protected void serviceInit(Configuration conf) throws Exception { YarnConfiguration.DEFAULT_RM_SCHEDULER_ADDRESS, YarnConfiguration.DEFAULT_RM_SCHEDULER_PORT); initializeProcessingChain(conf); + long appMaxTimeSeconds = conf.getLong(MAXIMUM_LIFETIME_KEY, 0); + this.appMaxTimeEnabled = (appMaxTimeSeconds > 0); + } + + // setter for clock. + public void setClock(Clock clock) { + this.clock = clock; } private void addPlacementConstraintHandler(Configuration conf) { @@ -428,6 +446,23 @@ public AllocateResponse allocate(AllocateRequest request) throw new InvalidApplicationMasterRequestException(message); } + ApplicationId applicationId = appAttemptId.getApplicationId(); + RMApp app = this.rmContext.getRMApps().get(applicationId); + // kill running application if its runtime exceeds specified maximum lifetime + if (appMaxTimeEnabled) { + long startTime = app.getStartTime(); + long elapsedTimeSeconds = (clock.getTime() - startTime)/1000; + if (elapsedTimeSeconds >= app.getMaximumLifetimeSeconds()) { + this.rmContext + .getDispatcher() + .getEventHandler() + .handle(new RMAppEvent(applicationId, RMAppEventType.KILL, + "Application " + applicationId + + " exceeded maximum lifetime limit of " + + app.getMaximumLifetimeSeconds() + " seconds.")); + } + } + AllocateResponse response = recordFactory.newRecordInstance(AllocateResponse.class); this.amsProcessingChain.allocate( @@ -440,8 +475,6 @@ public AllocateResponse allocate(AllocateRequest request) if (nextMasterKey != null && nextMasterKey.getMasterKey().getKeyId() != amrmTokenIdentifier .getKeyId()) { - RMApp app = - this.rmContext.getRMApps().get(appAttemptId.getApplicationId()); RMAppAttempt appAttempt = app.getRMAppAttempt(appAttemptId); RMAppAttemptImpl appAttemptImpl = (RMAppAttemptImpl)appAttempt; Token amrmToken = appAttempt.getAMRMToken(); 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/RMApp.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMApp.java index 99cce87102d..2749a9b9f40 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMApp.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/RMApp.java @@ -73,6 +73,12 @@ */ RMAppState getState(); + /** + * the maximum lifetime of the application + * @return the maximum lifetime of the application + */ + long getMaximumLifetimeSeconds(); + /** * The user who submitted this application. * @return the user who submitted the application. 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 9f1ea4403f4..7be4db569d9 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 @@ -146,6 +146,7 @@ private final int maxAppAttempts; private final ReadLock readLock; private final WriteLock writeLock; + private final long maxApplicationLifetime; private final Map attempts = new LinkedHashMap(); private final long submitTime; @@ -417,6 +418,8 @@ private static final int DUMMY_APPLICATION_ATTEMPT_NUMBER = -1; private static final float MINIMUM_AM_BLACKLIST_THRESHOLD_VALUE = 0.0f; private static final float MAXIMUM_AM_BLACKLIST_THRESHOLD_VALUE = 1.0f; + private static final String MAXIMUM_LIFETIME_KEY = + YarnConfiguration.RM_PREFIX + "application.maximum-lifetime-seconds"; public RMAppImpl(ApplicationId applicationId, RMContext rmContext, Configuration config, String name, String user, String queue, @@ -459,6 +462,10 @@ public RMAppImpl(ApplicationId applicationId, RMContext rmContext, this.applicationType = StringInterner.weakIntern(applicationType); this.applicationTags = applicationTags; this.amReqs = amReqs; + + Map env = submissionContext.getAMContainerSpec().getEnvironment(); + this.maxApplicationLifetime = computeMaximumLifetimeSeconds(env.get("YARN_APPLICATION_MAX_LIFETIME_SEC")); + if (submissionContext.getPriority() != null) { this.applicationPriority = Priority .newInstance(submissionContext.getPriority().getPriority()); @@ -572,6 +579,27 @@ public void stopTimelineCollector() { rmContext.getRMTimelineCollectorManager().remove(applicationId); } + private long computeMaximumLifetimeSeconds(String value){ + long hardLimit = conf.getLong(MAXIMUM_LIFETIME_KEY, Long.MAX_VALUE); + + if (value == null){ + return hardLimit; + } + + long softLimit = -1; + try { + softLimit = Long.parseLong(value); + } + catch (NumberFormatException e) { + } + if (softLimit <= 0) { + softLimit = Long.MAX_VALUE; + LOG.info("Specified application maximum lifetime " + + value + " is not valid."); + } + return Math.min(hardLimit, softLimit); + } + @Override public ApplicationId getApplicationId() { return this.applicationId; @@ -664,6 +692,11 @@ public String getName() { return this.name; } + @Override + public long getMaximumLifetimeSeconds() { + return maxApplicationLifetime; + } + @Override public RMAppAttempt getCurrentAppAttempt() { return this.currentAttempt; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationMasterService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationMasterService.java index 9696741f1ee..244cf4a6d30 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationMasterService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationMasterService.java @@ -69,6 +69,7 @@ import org.apache.hadoop.yarn.security.ContainerTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.resource.TestResourceProfiles; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptState; import org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainer; @@ -85,6 +86,7 @@ .FairSchedulerConfiguration; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler; import org.apache.hadoop.yarn.server.utils.BuilderUtils; +import org.apache.hadoop.yarn.util.ControlledClock; import org.apache.hadoop.yarn.util.resource.DominantResourceCalculator; import org.apache.hadoop.yarn.util.resource.ResourceUtils; import org.apache.hadoop.yarn.util.resource.Resources; @@ -99,6 +101,9 @@ private final int GB = 1024; private static YarnConfiguration conf; + private static final String MAXIMUM_LIFETIME_KEY = + YarnConfiguration.RM_PREFIX + "application.maximum-lifetime-seconds"; + private static AtomicInteger beforeRegCount = new AtomicInteger(0); private static AtomicInteger afterRegCount = new AtomicInteger(0); private static AtomicInteger beforeAllocCount = new AtomicInteger(0); @@ -256,6 +261,63 @@ public void testApplicationMasterInterceptor() throws Exception { rm.stop(); } + @Test(timeout=600000) + public void testApplicationMaxTimeout() throws Exception { + // Set Configuration + long maxLifeTimeSec = 76; + conf.setLong(MAXIMUM_LIFETIME_KEY, maxLifeTimeSec); + + MockRM rm = new MockRM(conf); + try { + rm.start(); + + // Register node1 + MockNM nm = rm.registerNode("127.0.0.1:1234", 6 * GB); + + // Submit an application + RMApp app = rm.submitApp(2048); + + // kick the scheduling + nm.nodeHeartbeat(true); + RMAppAttempt attempt = app.getCurrentAppAttempt(); + MockAM am = rm.sendAMLaunched(attempt.getAppAttemptId()); + am.registerAppAttempt(); + + // Set the last reponseId to be MAX_INT + Assert.assertTrue(am.setApplicationLastResponseId(Integer.MAX_VALUE)); + + // Both allocate should succeed + am.schedule(); // send allocate with reponseId = MAX_INT + + // Empty Allocate Request + AllocateRequestPBImpl allocateRequest = new AllocateRequestPBImpl(); + List release = new ArrayList(); + List ask = new ArrayList(); + allocateRequest.setReleaseList(release); + allocateRequest.setAskList(ask); + allocateRequest.setProgress((float)9); + + am.allocate(allocateRequest); // allocate a empty request. + rm.drainEvents(); + Assert.assertEquals(RMAppState.RUNNING, app.getState()); + + ControlledClock clock = new ControlledClock(null); + clock.setTime(app.getStartTime() + (maxLifeTimeSec * 1000)); + + // trigger application killing due to maximum lifetime. + rm.getApplicationMasterService().setClock(clock); + am.allocate(allocateRequest); // allocate a empty request. + rm.drainEvents(); + Assert.assertEquals(RMAppState.KILLED, app.getState()); + + } finally { + if (rm != null) { + rm.stop(); + } + } + } + + @Test(timeout = 3000000) public void testRMIdentifierOnContainerAllocation() throws Exception { MockRM rm = new MockRM(conf); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationsmanager/MockAsm.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationsmanager/MockAsm.java index 6c6c4b4e803..47a4ffd06c6 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationsmanager/MockAsm.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/applicationsmanager/MockAsm.java @@ -88,6 +88,11 @@ public long getStartTime() { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public long getMaximumLifetimeSeconds() { + return Long.MAX_VALUE; + } + @Override public long getSubmitTime() { throw new UnsupportedOperationException("Not supported yet."); 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/MockRMApp.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/MockRMApp.java index ad29d274a4f..4855fa2fd68 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/MockRMApp.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/MockRMApp.java @@ -99,7 +99,12 @@ public MockRMApp(int newid, long time, RMAppState newState, String userName, Str public ApplicationId getApplicationId() { return id; } - + + @Override + public long getMaximumLifetimeSeconds() { + return Long.MAX_VALUE; + } + @Override public ApplicationSubmissionContext getApplicationSubmissionContext() { return new ApplicationSubmissionContextPBImpl(); 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/TestRMAppImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppImpl.java index 129e9f9a90e..2492098ff0b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/rmapp/TestRMAppImpl.java @@ -1,4 +1,164 @@ +/** + * 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.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.yarn.MockApps; +import org.apache.hadoop.yarn.api.records.*; +import org.apache.hadoop.yarn.api.records.impl.pb.ApplicationSubmissionContextPBImpl; +import org.apache.hadoop.yarn.api.records.impl.pb.ContainerLaunchContextPBImpl; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.event.DrainDispatcher; +import org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService; +import org.apache.hadoop.yarn.server.resourcemanager.RMContext; +import org.apache.hadoop.yarn.server.resourcemanager.RMContextImpl; +import org.apache.hadoop.yarn.server.resourcemanager.ahs.RMApplicationHistoryWriter; +import org.apache.hadoop.yarn.server.resourcemanager.metrics.SystemMetricsPublisher; +import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.AMLivelinessMonitor; +import org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.ContainerAllocationExpirer; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler; +import org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager; +import org.apache.hadoop.yarn.server.resourcemanager.security.ClientToAMTokenSecretManagerInRM; +import org.apache.hadoop.yarn.server.resourcemanager.security.DelegationTokenRenewer; +import org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM; +import org.apache.hadoop.yarn.server.resourcemanager.security.RMContainerTokenSecretManager; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + public class TestRMAppImpl { + private static final Log LOG = LogFactory + .getLog(TestRMAppImpl.class); + + private RMContext rmContext; + private static final String MAXIMUM_LIFETIME_KEY = + YarnConfiguration.RM_PREFIX + "application.maximum-lifetime-seconds"; + + private static int appId = 1; + private DrainDispatcher rmDispatcher; + private RMStateStore store; + private RMApplicationHistoryWriter writer; + private SystemMetricsPublisher publisher; + private YarnScheduler scheduler; + private Configuration conf; + + @Before + public void setup() throws IOException{ + conf = new YarnConfiguration(); + store = mock(RMStateStore.class); + writer = mock(RMApplicationHistoryWriter.class); + + rmDispatcher = new DrainDispatcher(); + ContainerAllocationExpirer containerAllocationExpirer = + mock(ContainerAllocationExpirer.class); + AMLivelinessMonitor amLivelinessMonitor = mock(AMLivelinessMonitor.class); + AMLivelinessMonitor amFinishingMonitor = mock(AMLivelinessMonitor.class); + DelegationTokenRenewer renewer = mock(DelegationTokenRenewer.class); + + RMContext realRMContext = + new RMContextImpl(rmDispatcher, + containerAllocationExpirer, amLivelinessMonitor, amFinishingMonitor, + renewer, new AMRMTokenSecretManager(conf, this.rmContext), + new RMContainerTokenSecretManager(conf), + new NMTokenSecretManagerInRM(conf), + new ClientToAMTokenSecretManagerInRM()); + ((RMContextImpl)realRMContext).setStateStore(store); + publisher = mock(SystemMetricsPublisher.class); + realRMContext.setSystemMetricsPublisher(publisher); + realRMContext.setRMApplicationHistoryWriter(writer); + + this.rmContext = spy(realRMContext); + } + + + private RMApp createNewTestApp(ApplicationSubmissionContext submissionContext, Configuration app_conf) { + ApplicationId applicationId = MockApps.newAppID(appId++); + String user = MockApps.newUserName(); + String name = MockApps.newAppName(); + String queue = MockApps.newQueue(); + // ensure max application attempts set to known value + scheduler = mock(YarnScheduler.class); + + ApplicationMasterService masterService = + new ApplicationMasterService(rmContext, scheduler); + + if(submissionContext == null) { + submissionContext = new ApplicationSubmissionContextPBImpl(); + } + // applicationId will not be used because RMStateStore is mocked, + // but applicationId is still set for safety + submissionContext.setApplicationId(applicationId); + + RMApp application = new RMAppImpl(applicationId, rmContext, app_conf, name, + user, queue, submissionContext, scheduler, masterService, + System.currentTimeMillis(), "YARN", null, new ArrayList()); + + this.rmContext.getRMApps().putIfAbsent(application.getApplicationId(), + application); + return application; + } + + @Test + public void testMaximumLifetime() throws IOException{ + long hardlimit = 71; + long softlimit = 73; + + // hardlimit of application maximum lifetime is set via YARN config. + Configuration conf1 = new YarnConfiguration(); + conf1.setLong(MAXIMUM_LIFETIME_KEY, hardlimit); + + // softlimit of application maximum lifetime is set via environment variable. + ApplicationSubmissionContext submissionContext = new ApplicationSubmissionContextPBImpl(); + ContainerLaunchContext containerContext = new ContainerLaunchContextPBImpl(); + containerContext.setEnvironment(new HashMap()); + containerContext.getEnvironment().put("YARN_APPLICATION_MAX_LIFETIME_SEC", String.valueOf(softlimit)); + submissionContext.setAMContainerSpec(containerContext); + + // App1 - hardlimit < softlimit + RMApp app1 = createNewTestApp(submissionContext, conf1); + Assert.assertEquals(hardlimit, app1.getMaximumLifetimeSeconds()); + + //App2 - softlimit < hardlimit + hardlimit = 76; // Change hardlimit + Configuration conf2 = new YarnConfiguration(); + conf2.setLong(MAXIMUM_LIFETIME_KEY, hardlimit); + RMApp app2 = createNewTestApp(submissionContext, conf2); + Assert.assertEquals(softlimit, app2.getMaximumLifetimeSeconds()); + + //App3 - no softlimit specified. + containerContext.getEnvironment().remove("YARN_APPLICATION_MAX_LIFETIME_SEC"); + RMApp app3 = createNewTestApp(submissionContext, conf2); + Assert.assertEquals(hardlimit, app3.getMaximumLifetimeSeconds()); + + //App4 - invalid softlimit + containerContext.getEnvironment().put("YARN_APPLICATION_MAX_LIFETIME_SEC", "abcd"); + RMApp app4 = createNewTestApp(submissionContext, conf2); + Assert.assertEquals(hardlimit, app4.getMaximumLifetimeSeconds()); + } }