YARN-5649. Add REST endpoints for updating application timeouts. Contributed by Rohith Sharma K S
This commit is contained in:
parent
3d94da1e00
commit
1f12867a69
|
@ -1752,7 +1752,7 @@ public class ClientRMService extends AbstractService implements
|
||||||
RMAuditLogger.logFailure(callerUGI.getShortUserName(),
|
RMAuditLogger.logFailure(callerUGI.getShortUserName(),
|
||||||
AuditConstants.UPDATE_APP_TIMEOUTS, "UNKNOWN", "ClientRMService",
|
AuditConstants.UPDATE_APP_TIMEOUTS, "UNKNOWN", "ClientRMService",
|
||||||
ex.getMessage());
|
ex.getMessage());
|
||||||
throw RPCUtil.getRemoteException(ex);
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
RMAuditLogger.logSuccess(callerUGI.getShortUserName(),
|
RMAuditLogger.logSuccess(callerUGI.getShortUserName(),
|
||||||
|
|
|
@ -66,6 +66,7 @@ public class RMAuditLogger {
|
||||||
"Update Application Priority";
|
"Update Application Priority";
|
||||||
public static final String UPDATE_APP_TIMEOUTS =
|
public static final String UPDATE_APP_TIMEOUTS =
|
||||||
"Update Application Timeouts";
|
"Update Application Timeouts";
|
||||||
|
public static final String GET_APP_TIMEOUTS = "Get Application Timeouts";
|
||||||
public static final String CHANGE_CONTAINER_RESOURCE =
|
public static final String CHANGE_CONTAINER_RESOURCE =
|
||||||
"AM Changed Container Resource";
|
"AM Changed Container Resource";
|
||||||
public static final String SIGNAL_CONTAINER = "Signal Container Request";
|
public static final String SIGNAL_CONTAINER = "Signal Container Request";
|
||||||
|
|
|
@ -515,7 +515,7 @@ public class RMServerUtils {
|
||||||
String message =
|
String message =
|
||||||
"Expire time is not in ISO8601 format. ISO8601 supported "
|
"Expire time is not in ISO8601 format. ISO8601 supported "
|
||||||
+ "format is yyyy-MM-dd'T'HH:mm:ss.SSSZ";
|
+ "format is yyyy-MM-dd'T'HH:mm:ss.SSSZ";
|
||||||
throw new YarnException(message);
|
throw new YarnException(message, ex);
|
||||||
}
|
}
|
||||||
if (expireTime < currentTimeMillis) {
|
if (expireTime < currentTimeMillis) {
|
||||||
String message =
|
String message =
|
||||||
|
|
|
@ -54,7 +54,8 @@ public class JAXBContextResolver implements ContextResolver<JAXBContext> {
|
||||||
CapacitySchedulerQueueInfoList.class, ResourceInfo.class,
|
CapacitySchedulerQueueInfoList.class, ResourceInfo.class,
|
||||||
UsersInfo.class, UserInfo.class, ApplicationStatisticsInfo.class,
|
UsersInfo.class, UserInfo.class, ApplicationStatisticsInfo.class,
|
||||||
StatisticsItemInfo.class, CapacitySchedulerHealthInfo.class,
|
StatisticsItemInfo.class, CapacitySchedulerHealthInfo.class,
|
||||||
FairSchedulerQueueInfoList.class};
|
FairSchedulerQueueInfoList.class, AppTimeoutsInfo.class,
|
||||||
|
AppTimeoutInfo.class };
|
||||||
// these dao classes need root unwrapping
|
// these dao classes need root unwrapping
|
||||||
final Class[] rootUnwrappedTypes =
|
final Class[] rootUnwrappedTypes =
|
||||||
{ NewApplication.class, ApplicationSubmissionContextInfo.class,
|
{ NewApplication.class, ApplicationSubmissionContextInfo.class,
|
||||||
|
|
|
@ -24,9 +24,11 @@ import java.nio.ByteBuffer;
|
||||||
import java.security.AccessControlException;
|
import java.security.AccessControlException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -96,10 +98,12 @@ import org.apache.hadoop.yarn.api.protocolrecords.ReservationUpdateRequest;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest;
|
import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationResponse;
|
import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationResponse;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationPriorityRequest;
|
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.ApplicationAccessType;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationReport;
|
import org.apache.hadoop.yarn.api.records.ApplicationReport;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
|
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
|
||||||
|
import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
|
||||||
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
|
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
|
||||||
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
import org.apache.hadoop.yarn.api.records.LocalResource;
|
import org.apache.hadoop.yarn.api.records.LocalResource;
|
||||||
|
@ -189,6 +193,7 @@ import org.apache.hadoop.yarn.server.webapp.dao.ContainerInfo;
|
||||||
import org.apache.hadoop.yarn.server.webapp.dao.ContainersInfo;
|
import org.apache.hadoop.yarn.server.webapp.dao.ContainersInfo;
|
||||||
import org.apache.hadoop.yarn.util.AdHocLogDumper;
|
import org.apache.hadoop.yarn.util.AdHocLogDumper;
|
||||||
import org.apache.hadoop.yarn.util.ConverterUtils;
|
import org.apache.hadoop.yarn.util.ConverterUtils;
|
||||||
|
import org.apache.hadoop.yarn.util.Times;
|
||||||
import org.apache.hadoop.yarn.webapp.BadRequestException;
|
import org.apache.hadoop.yarn.webapp.BadRequestException;
|
||||||
import org.apache.hadoop.yarn.webapp.ForbiddenException;
|
import org.apache.hadoop.yarn.webapp.ForbiddenException;
|
||||||
import org.apache.hadoop.yarn.webapp.NotFoundException;
|
import org.apache.hadoop.yarn.webapp.NotFoundException;
|
||||||
|
@ -2428,4 +2433,185 @@ public class RMWebServices extends WebServices {
|
||||||
return Response.status(Status.OK).entity(resResponse).build();
|
return Response.status(Status.OK).entity(resResponse).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/apps/{appid}/timeout/{type}")
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
|
||||||
|
MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
|
||||||
|
public AppTimeoutInfo getAppTimeout(@Context HttpServletRequest hsr,
|
||||||
|
@PathParam("appid") String appId, @PathParam("type") String type)
|
||||||
|
throws AuthorizationException {
|
||||||
|
init();
|
||||||
|
RMApp app = validateAppTimeoutRequest(hsr, appId);
|
||||||
|
|
||||||
|
ApplicationTimeoutType appTimeoutType = parseTimeoutType(type);
|
||||||
|
Long timeoutValue = app.getApplicationTimeouts().get(appTimeoutType);
|
||||||
|
AppTimeoutInfo timeout =
|
||||||
|
constructAppTimeoutDao(appTimeoutType, timeoutValue);
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RMApp validateAppTimeoutRequest(HttpServletRequest hsr,
|
||||||
|
String appId) {
|
||||||
|
UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
|
||||||
|
String userName = "UNKNOWN-USER";
|
||||||
|
if (callerUGI != null) {
|
||||||
|
userName = callerUGI.getUserName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
|
||||||
|
String msg = "The default static user cannot carry out this operation.";
|
||||||
|
RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_TIMEOUTS,
|
||||||
|
"UNKNOWN", "RMWebService", msg);
|
||||||
|
throw new ForbiddenException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/apps/{appid}/timeouts")
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
|
||||||
|
MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
|
||||||
|
public AppTimeoutsInfo getAppTimeouts(@Context HttpServletRequest hsr,
|
||||||
|
@PathParam("appid") String appId) throws AuthorizationException {
|
||||||
|
init();
|
||||||
|
|
||||||
|
RMApp app = validateAppTimeoutRequest(hsr, appId);
|
||||||
|
|
||||||
|
AppTimeoutsInfo timeouts = new AppTimeoutsInfo();
|
||||||
|
Map<ApplicationTimeoutType, Long> applicationTimeouts =
|
||||||
|
app.getApplicationTimeouts();
|
||||||
|
if (applicationTimeouts.isEmpty()) {
|
||||||
|
// If application is not set timeout, lifetime should be sent as default
|
||||||
|
// with expiryTime=UNLIMITED and remainingTime=-1
|
||||||
|
timeouts
|
||||||
|
.add(constructAppTimeoutDao(ApplicationTimeoutType.LIFETIME, null));
|
||||||
|
} else {
|
||||||
|
for (Entry<ApplicationTimeoutType, Long> timeout : app
|
||||||
|
.getApplicationTimeouts().entrySet()) {
|
||||||
|
AppTimeoutInfo timeoutInfo =
|
||||||
|
constructAppTimeoutDao(timeout.getKey(), timeout.getValue());
|
||||||
|
timeouts.add(timeoutInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return timeouts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApplicationTimeoutType parseTimeoutType(String type) {
|
||||||
|
try {
|
||||||
|
// enum string is in the uppercase
|
||||||
|
return ApplicationTimeoutType
|
||||||
|
.valueOf(StringUtils.toUpperCase(type.trim()));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
ApplicationTimeoutType[] typeArray = ApplicationTimeoutType.values();
|
||||||
|
String allAppTimeoutTypes = Arrays.toString(typeArray);
|
||||||
|
throw new BadRequestException("Invalid application-state " + type.trim()
|
||||||
|
+ " specified. It should be one of " + allAppTimeoutTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AppTimeoutInfo constructAppTimeoutDao(ApplicationTimeoutType type,
|
||||||
|
Long timeoutInMillis) {
|
||||||
|
AppTimeoutInfo timeout = new AppTimeoutInfo();
|
||||||
|
timeout.setTimeoutType(type);
|
||||||
|
if (timeoutInMillis != null) {
|
||||||
|
timeout.setExpiryTime(Times.formatISO8601(timeoutInMillis.longValue()));
|
||||||
|
timeout.setRemainingTime(
|
||||||
|
Math.max((timeoutInMillis - System.currentTimeMillis()) / 1000, 0));
|
||||||
|
}
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/apps/{appid}/timeout")
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
|
||||||
|
MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||||
|
public Response updateApplicationTimeout(AppTimeoutInfo appTimeout,
|
||||||
|
@Context HttpServletRequest hsr, @PathParam("appid") String appId)
|
||||||
|
throws AuthorizationException, YarnException, InterruptedException,
|
||||||
|
IOException {
|
||||||
|
init();
|
||||||
|
|
||||||
|
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 update timeout of an absent application " + appId);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateApplicationTimeouts(app, callerUGI, appTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response updateApplicationTimeouts(final RMApp app,
|
||||||
|
UserGroupInformation callerUGI, final AppTimeoutInfo appTimeout)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
if (appTimeout.getTimeoutType() == null) {
|
||||||
|
return Response.status(Status.BAD_REQUEST).entity("Timeout type is null.")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
String userName = callerUGI.getUserName();
|
||||||
|
try {
|
||||||
|
callerUGI.doAs(new PrivilegedExceptionAction<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void run() throws IOException, YarnException {
|
||||||
|
UpdateApplicationTimeoutsRequest request =
|
||||||
|
UpdateApplicationTimeoutsRequest
|
||||||
|
.newInstance(app.getApplicationId(), Collections.singletonMap(
|
||||||
|
appTimeout.getTimeoutType(), appTimeout.getExpireTime()));
|
||||||
|
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 timeout of app " + appId
|
||||||
|
+ " by remote user " + userName;
|
||||||
|
return Response.status(Status.FORBIDDEN).entity(msg).build();
|
||||||
|
} else if (ye.getCause() instanceof ParseException) {
|
||||||
|
return Response.status(Status.BAD_REQUEST)
|
||||||
|
.entity(ye.getMessage()).build();
|
||||||
|
} else {
|
||||||
|
throw ue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppTimeoutInfo timeout = constructAppTimeoutDao(appTimeout.getTimeoutType(),
|
||||||
|
app.getApplicationTimeouts().get(appTimeout.getTimeoutType()));
|
||||||
|
return Response.status(Status.OK).entity(timeout).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
@ -29,6 +30,7 @@ import javax.xml.bind.annotation.XmlTransient;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationResourceUsageReport;
|
import org.apache.hadoop.yarn.api.records.ApplicationResourceUsageReport;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
|
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
|
||||||
|
import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
|
||||||
import org.apache.hadoop.yarn.api.records.Container;
|
import org.apache.hadoop.yarn.api.records.Container;
|
||||||
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
import org.apache.hadoop.yarn.api.records.LogAggregationStatus;
|
import org.apache.hadoop.yarn.api.records.LogAggregationStatus;
|
||||||
|
@ -114,6 +116,7 @@ public class AppInfo {
|
||||||
protected String amNodeLabelExpression;
|
protected String amNodeLabelExpression;
|
||||||
|
|
||||||
protected ResourcesInfo resourceInfo = null;
|
protected ResourcesInfo resourceInfo = null;
|
||||||
|
protected AppTimeoutsInfo timeouts = new AppTimeoutsInfo();
|
||||||
|
|
||||||
public AppInfo() {
|
public AppInfo() {
|
||||||
} // JAXB needs this
|
} // JAXB needs this
|
||||||
|
@ -240,6 +243,27 @@ public class AppInfo {
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<ApplicationTimeoutType, Long> applicationTimeouts =
|
||||||
|
app.getApplicationTimeouts();
|
||||||
|
if (applicationTimeouts.isEmpty()) {
|
||||||
|
// If application is not set timeout, lifetime should be sent as default
|
||||||
|
// with expiryTime=UNLIMITED and remainingTime=-1
|
||||||
|
AppTimeoutInfo timeoutInfo = new AppTimeoutInfo();
|
||||||
|
timeoutInfo.setTimeoutType(ApplicationTimeoutType.LIFETIME);
|
||||||
|
timeouts.add(timeoutInfo);
|
||||||
|
} else {
|
||||||
|
for (Map.Entry<ApplicationTimeoutType, Long> entry : app
|
||||||
|
.getApplicationTimeouts().entrySet()) {
|
||||||
|
AppTimeoutInfo timeout = new AppTimeoutInfo();
|
||||||
|
timeout.setTimeoutType(entry.getKey());
|
||||||
|
long timeoutInMillis = entry.getValue().longValue();
|
||||||
|
timeout.setExpiryTime(Times.formatISO8601(timeoutInMillis));
|
||||||
|
timeout.setRemainingTime(Math
|
||||||
|
.max((timeoutInMillis - System.currentTimeMillis()) / 1000, 0));
|
||||||
|
timeouts.add(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* 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.webapp.dao;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DAO object to display Application timeout information.
|
||||||
|
*/
|
||||||
|
@XmlRootElement(name = "timeout")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class AppTimeoutInfo {
|
||||||
|
|
||||||
|
@XmlElement(name = "type")
|
||||||
|
private ApplicationTimeoutType timeoutType;
|
||||||
|
|
||||||
|
@XmlElement(name = "expiryTime")
|
||||||
|
private String expiryTime;
|
||||||
|
|
||||||
|
@XmlElement(name = "remainingTimeInSeconds")
|
||||||
|
private long remainingTimeInSec;
|
||||||
|
|
||||||
|
public AppTimeoutInfo() {
|
||||||
|
expiryTime = "UNLIMITED";
|
||||||
|
remainingTimeInSec = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationTimeoutType getTimeoutType() {
|
||||||
|
return timeoutType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpireTime() {
|
||||||
|
return expiryTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRemainingTimeInSec() {
|
||||||
|
return remainingTimeInSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeoutType(ApplicationTimeoutType type) {
|
||||||
|
this.timeoutType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiryTime(String expiryTime) {
|
||||||
|
this.expiryTime = expiryTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemainingTime(long remainingTime) {
|
||||||
|
this.remainingTimeInSec = remainingTime;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* 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.webapp.dao;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class hosts a set of AppTimeout DAO objects.
|
||||||
|
*/
|
||||||
|
@XmlRootElement(name = "timeouts")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public class AppTimeoutsInfo {
|
||||||
|
|
||||||
|
@XmlElement(name = "timeout")
|
||||||
|
private ArrayList<AppTimeoutInfo> timeouts = new ArrayList<AppTimeoutInfo>();
|
||||||
|
|
||||||
|
public AppTimeoutsInfo() {
|
||||||
|
} // JAXB needs this
|
||||||
|
|
||||||
|
public void add(AppTimeoutInfo timeoutInfo) {
|
||||||
|
timeouts.add(timeoutInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<AppTimeoutInfo> getAppTimeouts() {
|
||||||
|
return timeouts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager.rmapp;
|
package org.apache.hadoop.yarn.server.resourcemanager.rmapp;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -319,7 +320,7 @@ public class MockRMApp implements RMApp {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<ApplicationTimeoutType, Long> getApplicationTimeouts() {
|
public Map<ApplicationTimeoutType, Long> getApplicationTimeouts() {
|
||||||
throw new UnsupportedOperationException("Not supported yet.");
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1419,7 +1419,7 @@ public class TestRMWebServicesApps extends JerseyTestBase {
|
||||||
public void verifyAppInfo(JSONObject info, RMApp app) throws JSONException,
|
public void verifyAppInfo(JSONObject info, RMApp app) throws JSONException,
|
||||||
Exception {
|
Exception {
|
||||||
|
|
||||||
int expectedNumberOfElements = 34;
|
int expectedNumberOfElements = 35;
|
||||||
String appNodeLabelExpression = null;
|
String appNodeLabelExpression = null;
|
||||||
String amNodeLabelExpression = null;
|
String amNodeLabelExpression = null;
|
||||||
if (app.getApplicationSubmissionContext()
|
if (app.getApplicationSubmissionContext()
|
||||||
|
|
|
@ -61,6 +61,7 @@ import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHand
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationAccessType;
|
import org.apache.hadoop.yarn.api.records.ApplicationAccessType;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
|
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
|
||||||
|
import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
|
||||||
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
|
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
|
||||||
import org.apache.hadoop.yarn.api.records.LocalResource;
|
import org.apache.hadoop.yarn.api.records.LocalResource;
|
||||||
import org.apache.hadoop.yarn.api.records.LocalResourceType;
|
import org.apache.hadoop.yarn.api.records.LocalResourceType;
|
||||||
|
@ -83,15 +84,17 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairSchedule
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppPriority;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppPriority;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppQueue;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppQueue;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppState;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppState;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppTimeoutInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationSubmissionContextInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationSubmissionContextInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CredentialsInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CredentialsInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LocalResourceInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LocalResourceInfo;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LogAggregationContextInfo;
|
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LogAggregationContextInfo;
|
||||||
import org.apache.hadoop.yarn.util.ConverterUtils;
|
import org.apache.hadoop.yarn.util.Times;
|
||||||
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
|
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
|
||||||
import org.apache.hadoop.yarn.webapp.GuiceServletConfig;
|
import org.apache.hadoop.yarn.webapp.GuiceServletConfig;
|
||||||
import org.apache.hadoop.yarn.webapp.JerseyTestBase;
|
import org.apache.hadoop.yarn.webapp.JerseyTestBase;
|
||||||
import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
|
import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
|
||||||
|
import org.codehaus.jettison.json.JSONArray;
|
||||||
import org.codehaus.jettison.json.JSONException;
|
import org.codehaus.jettison.json.JSONException;
|
||||||
import org.codehaus.jettison.json.JSONObject;
|
import org.codehaus.jettison.json.JSONObject;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -117,6 +120,7 @@ import com.sun.jersey.api.client.ClientResponse.Status;
|
||||||
import com.sun.jersey.api.client.WebResource;
|
import com.sun.jersey.api.client.WebResource;
|
||||||
import com.sun.jersey.api.client.config.DefaultClientConfig;
|
import com.sun.jersey.api.client.config.DefaultClientConfig;
|
||||||
import com.sun.jersey.api.client.filter.LoggingFilter;
|
import com.sun.jersey.api.client.filter.LoggingFilter;
|
||||||
|
import com.sun.jersey.api.json.JSONConfiguration;
|
||||||
import com.sun.jersey.api.json.JSONJAXBContext;
|
import com.sun.jersey.api.json.JSONJAXBContext;
|
||||||
import com.sun.jersey.api.json.JSONMarshaller;
|
import com.sun.jersey.api.json.JSONMarshaller;
|
||||||
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
|
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
|
||||||
|
@ -1295,4 +1299,135 @@ public class TestRMWebServicesAppsModification extends JerseyTestBase {
|
||||||
assertEquals(queue, responseQueue);
|
assertEquals(queue, responseQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 90000)
|
||||||
|
public void testUpdateAppTimeout() throws Exception {
|
||||||
|
client().addFilter(new LoggingFilter(System.out));
|
||||||
|
|
||||||
|
rm.start();
|
||||||
|
rm.registerNode("127.0.0.1:1234", 2048);
|
||||||
|
String[] mediaTypes =
|
||||||
|
{ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML };
|
||||||
|
MediaType[] contentTypes =
|
||||||
|
{ MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE };
|
||||||
|
for (String mediaType : mediaTypes) {
|
||||||
|
for (MediaType contentType : contentTypes) {
|
||||||
|
// application submitted without timeout
|
||||||
|
RMApp app = rm.submitApp(CONTAINER_MB, "", webserviceUserName);
|
||||||
|
|
||||||
|
ClientResponse response =
|
||||||
|
this.constructWebResource("apps", app.getApplicationId().toString(),
|
||||||
|
"timeouts").accept(mediaType).get(ClientResponse.class);
|
||||||
|
if (mediaType.contains(MediaType.APPLICATION_JSON)) {
|
||||||
|
assertEquals(
|
||||||
|
MediaType.APPLICATION_JSON_TYPE + "; " + JettyUtils.UTF_8,
|
||||||
|
response.getType().toString());
|
||||||
|
JSONObject js =
|
||||||
|
response.getEntity(JSONObject.class).getJSONObject("timeouts");
|
||||||
|
JSONArray entity = js.getJSONArray("timeout");
|
||||||
|
verifyAppTimeoutJson(entity.getJSONObject(0),
|
||||||
|
ApplicationTimeoutType.LIFETIME, "UNLIMITED", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppTimeoutInfo timeoutUpdate = new AppTimeoutInfo();
|
||||||
|
long timeOutFromNow = 60;
|
||||||
|
String expireTime = Times
|
||||||
|
.formatISO8601(System.currentTimeMillis() + timeOutFromNow * 1000);
|
||||||
|
timeoutUpdate.setTimeoutType(ApplicationTimeoutType.LIFETIME);
|
||||||
|
timeoutUpdate.setExpiryTime(expireTime);
|
||||||
|
|
||||||
|
Object entity;
|
||||||
|
if (contentType.equals(MediaType.APPLICATION_JSON_TYPE)) {
|
||||||
|
entity = appTimeoutToJSON(timeoutUpdate);
|
||||||
|
} else {
|
||||||
|
entity = timeoutUpdate;
|
||||||
|
}
|
||||||
|
response = this
|
||||||
|
.constructWebResource("apps", app.getApplicationId().toString(),
|
||||||
|
"timeout")
|
||||||
|
.entity(entity, contentType).accept(mediaType)
|
||||||
|
.put(ClientResponse.class);
|
||||||
|
|
||||||
|
if (!isAuthenticationEnabled()) {
|
||||||
|
assertResponseStatusCode(Status.UNAUTHORIZED,
|
||||||
|
response.getStatusInfo());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assertResponseStatusCode(Status.OK, response.getStatusInfo());
|
||||||
|
if (mediaType.contains(MediaType.APPLICATION_JSON)) {
|
||||||
|
verifyAppTimeoutJson(response, ApplicationTimeoutType.LIFETIME,
|
||||||
|
expireTime, timeOutFromNow);
|
||||||
|
} else {
|
||||||
|
verifyAppTimeoutXML(response, ApplicationTimeoutType.LIFETIME,
|
||||||
|
expireTime, timeOutFromNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoke get
|
||||||
|
response =
|
||||||
|
this.constructWebResource("apps", app.getApplicationId().toString(),
|
||||||
|
"timeout", ApplicationTimeoutType.LIFETIME.toString())
|
||||||
|
.accept(mediaType).get(ClientResponse.class);
|
||||||
|
assertResponseStatusCode(Status.OK, response.getStatusInfo());
|
||||||
|
if (mediaType.contains(MediaType.APPLICATION_JSON)) {
|
||||||
|
verifyAppTimeoutJson(response, ApplicationTimeoutType.LIFETIME,
|
||||||
|
expireTime, timeOutFromNow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void verifyAppTimeoutJson(ClientResponse response,
|
||||||
|
ApplicationTimeoutType type, String expireTime, long timeOutFromNow)
|
||||||
|
throws JSONException {
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE + "; " + JettyUtils.UTF_8,
|
||||||
|
response.getType().toString());
|
||||||
|
JSONObject jsonTimeout = response.getEntity(JSONObject.class);
|
||||||
|
assertEquals("incorrect number of elements", 1, jsonTimeout.length());
|
||||||
|
JSONObject json = jsonTimeout.getJSONObject("timeout");
|
||||||
|
verifyAppTimeoutJson(json, type, expireTime, timeOutFromNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void verifyAppTimeoutJson(JSONObject json,
|
||||||
|
ApplicationTimeoutType type, String expireTime, long timeOutFromNow)
|
||||||
|
throws JSONException {
|
||||||
|
assertEquals("incorrect number of elements", 3, json.length());
|
||||||
|
assertEquals(type.toString(), json.getString("type"));
|
||||||
|
assertEquals(expireTime, json.getString("expiryTime"));
|
||||||
|
assertTrue(json.getLong("remainingTimeInSeconds") <= timeOutFromNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void verifyAppTimeoutXML(ClientResponse response,
|
||||||
|
ApplicationTimeoutType type, String expireTime, long timeOutFromNow)
|
||||||
|
throws ParserConfigurationException, IOException, SAXException {
|
||||||
|
assertEquals(MediaType.APPLICATION_XML_TYPE + "; " + JettyUtils.UTF_8,
|
||||||
|
response.getType().toString());
|
||||||
|
String xml = response.getEntity(String.class);
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||||
|
InputSource is = new InputSource();
|
||||||
|
is.setCharacterStream(new StringReader(xml));
|
||||||
|
Document dom = db.parse(is);
|
||||||
|
NodeList nodes = dom.getElementsByTagName("timeout");
|
||||||
|
assertEquals("incorrect number of elements", 1, nodes.getLength());
|
||||||
|
Element element = (Element) nodes.item(0);
|
||||||
|
assertEquals(type.toString(),
|
||||||
|
WebServicesTestUtils.getXmlString(element, "type"));
|
||||||
|
assertEquals(expireTime,
|
||||||
|
WebServicesTestUtils.getXmlString(element, "expiryTime"));
|
||||||
|
assertTrue(WebServicesTestUtils.getXmlLong(element,
|
||||||
|
"remainingTimeInSeconds") < timeOutFromNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String appTimeoutToJSON(AppTimeoutInfo timeout)
|
||||||
|
throws Exception {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
JSONJAXBContext ctx = new JSONJAXBContext(
|
||||||
|
JSONConfiguration.natural().rootUnwrapping(false).build(),
|
||||||
|
AppTimeoutInfo.class);
|
||||||
|
JSONMarshaller jm = ctx.createJSONMarshaller();
|
||||||
|
jm.marshallToJSON(timeout, sw);
|
||||||
|
jm.marshallToJSON(timeout, System.out);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue