diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAuditLogger.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAuditLogger.java index bba2a90..e21b421 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAuditLogger.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAuditLogger.java @@ -63,6 +63,7 @@ "Update Application Priority"; public static final String UPDATE_APP_TIMEOUTS = "Update Application Timeouts"; + public static final String GET_APP_TIMEOUTS = "Get Application Timeouts"; public static final String CHANGE_CONTAINER_RESOURCE = "AM Changed Container Resource"; public static final String SIGNAL_CONTAINER = "Signal Container Request"; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java index ef6fd06..2e8ad6b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java @@ -95,10 +95,12 @@ import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest; import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationResponse; import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationPriorityRequest; +import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationTimeoutsRequest; import org.apache.hadoop.yarn.api.records.ApplicationAccessType; 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.ApplicationTimeouts; import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; import org.apache.hadoop.yarn.api.records.LocalResource; @@ -2387,4 +2389,124 @@ public ReservationListResponse run() throws IOException, return Response.status(Status.OK).entity(resResponse).build(); } + @GET + @Path("/apps/{appid}/timeouts") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public AppTimeouts getAppTimeouts(@Context HttpServletRequest hsr, + @PathParam("appid") String appId) throws AuthorizationException { + init(); + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); + String userName = "UNKNOWN-USER"; + if (callerUGI != null) { + userName = callerUGI.getUserName(); + } + + RMApp app = null; + try { + app = getRMAppForAppId(appId); + } catch (NotFoundException e) { + RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_TIMEOUTS, + "UNKNOWN", "RMWebService", + "Trying to get timeouts of an absent application " + appId); + throw e; + } + + AppTimeouts ret = new AppTimeouts(); + ApplicationTimeouts applicationTimeouts = + app.getApplicationSubmissionContext().getApplicationTimeouts(); + if (applicationTimeouts == null || applicationTimeouts.getLifetime() <= 0) { + ret.setLifetime(-1); + ret.setRemainingLifetime(-1); + } else { + long lifetime = applicationTimeouts.getLifetime(); + long remainingTime = lifetime + - ((System.currentTimeMillis() - app.getSubmitTime()) / 1000); + // negative indicates time to kill, but application might not killed + // because of monitoring interval buffer. So, set as remaining time as 0. + remainingTime = remainingTime < 0 ? 0 : remainingTime; + ret.setLifetime(lifetime); + ret.setRemainingLifetime(remainingTime); + } + + return ret; + } + + @PUT + @Path("/apps/{appid}/timeouts") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response updateApplicationPriority(AppTimeouts appTimeouts, + @Context HttpServletRequest hsr, @PathParam("appid") String appId) + throws AuthorizationException, YarnException, InterruptedException, + IOException { + init(); + if (appTimeouts == null) { + throw new YarnException("AppTimeouts cannot be null"); + } + + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); + if (callerUGI == null) { + throw new AuthorizationException( + "Unable to obtain user name, user not authenticated"); + } + + if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { + return Response.status(Status.FORBIDDEN) + .entity("The default static user cannot carry out this operation.") + .build(); + } + + String userName = callerUGI.getUserName(); + RMApp app = null; + try { + app = getRMAppForAppId(appId); + } catch (NotFoundException e) { + RMAuditLogger.logFailure(userName, AuditConstants.UPDATE_APP_TIMEOUTS, + "UNKNOWN", "RMWebService", + "Trying to move an absent application " + appId); + throw e; + } + + return updateApplicationTimeouts(app, callerUGI, appTimeouts); + } + + private Response updateApplicationTimeouts(final RMApp app, + UserGroupInformation callerUGI, final AppTimeouts appTimeouts) + throws IOException, InterruptedException { + String userName = callerUGI.getUserName(); + try { + callerUGI.doAs(new PrivilegedExceptionAction() { + @Override + public Void run() throws IOException, YarnException { + ApplicationTimeouts timeouts = + ApplicationTimeouts.newInstance(appTimeouts.getLifetime()); + UpdateApplicationTimeoutsRequest request = + UpdateApplicationTimeoutsRequest + .newInstance(app.getApplicationId(), timeouts); + rm.getClientRMService().updateApplicationTimeouts(request); + return null; + } + }); + } catch (UndeclaredThrowableException ue) { + // if the root cause is a permissions issue + // bubble that up to the user + if (ue.getCause() instanceof YarnException) { + YarnException ye = (YarnException) ue.getCause(); + if (ye.getCause() instanceof AccessControlException) { + String appId = app.getApplicationId().toString(); + String msg = "Unauthorized attempt to change priority of appid " + + appId + " by remote user " + userName; + return Response.status(Status.FORBIDDEN).entity(msg).build(); + } else { + throw ue; + } + } else { + throw ue; + } + } + AppTimeouts ret = new AppTimeouts(app.getApplicationSubmissionContext() + .getApplicationTimeouts().getLifetime()); + return Response.status(Status.OK).entity(ret).build(); + } + }