Java tutorial
/** * 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; import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.nio.ByteBuffer; import java.security.AccessControlException; import java.security.Principal; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeys; import org.apache.hadoop.io.DataOutputBuffer; import org.apache.hadoop.io.Text; import org.apache.hadoop.security.Credentials; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; import org.apache.hadoop.security.authorize.AuthorizationException; import org.apache.hadoop.security.token.SecretManager.InvalidToken; import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationHandler; import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenRequest; import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenResponse; import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetDelegationTokenRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetDelegationTokenResponse; import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationResponse; import org.apache.hadoop.yarn.api.protocolrecords.GetNewReservationRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetNewReservationResponse; import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationRequest; import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationResponse; import org.apache.hadoop.yarn.api.protocolrecords.MoveApplicationAcrossQueuesRequest; import org.apache.hadoop.yarn.api.protocolrecords.RenewDelegationTokenRequest; import org.apache.hadoop.yarn.api.protocolrecords.RenewDelegationTokenResponse; import org.apache.hadoop.yarn.api.protocolrecords.ReservationDeleteRequest; import org.apache.hadoop.yarn.api.protocolrecords.ReservationListRequest; import org.apache.hadoop.yarn.api.protocolrecords.ReservationListResponse; import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionRequest; import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionResponse; import org.apache.hadoop.yarn.api.protocolrecords.ReservationUpdateRequest; 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.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.ContainerLaunchContext; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; import org.apache.hadoop.yarn.api.records.LocalResource; import org.apache.hadoop.yarn.api.records.NodeId; import org.apache.hadoop.yarn.api.records.NodeLabel; import org.apache.hadoop.yarn.api.records.NodeState; import org.apache.hadoop.yarn.api.records.Priority; import org.apache.hadoop.yarn.api.records.QueueACL; import org.apache.hadoop.yarn.api.records.ReservationDefinition; import org.apache.hadoop.yarn.api.records.ReservationId; import org.apache.hadoop.yarn.api.records.ReservationRequest; import org.apache.hadoop.yarn.api.records.ReservationRequestInterpreter; import org.apache.hadoop.yarn.api.records.ReservationRequests; import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.api.records.URL; import org.apache.hadoop.yarn.api.records.YarnApplicationState; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger; import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger.AuditConstants; import org.apache.hadoop.yarn.server.resourcemanager.RMServerUtils; import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; import org.apache.hadoop.yarn.server.resourcemanager.nodelabels.NodeLabelsUtils; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo; 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.AppState; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationStatisticsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationSubmissionContextInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CredentialsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.DelegationToken; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.FairSchedulerInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.FifoSchedulerInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LabelsToNodesInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LocalResourceInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NewApplication; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NewReservation; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntry; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDefinitionInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteResponseInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationListInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationRequestsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateResponseInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.StatisticsItemInfo; import org.apache.hadoop.yarn.server.security.ApplicationACLsManager; import org.apache.hadoop.yarn.server.utils.BuilderUtils; import org.apache.hadoop.yarn.util.AdHocLogDumper; import org.apache.hadoop.yarn.util.ConverterUtils; import org.apache.hadoop.yarn.webapp.BadRequestException; import org.apache.hadoop.yarn.webapp.ForbiddenException; import org.apache.hadoop.yarn.webapp.NotFoundException; import org.apache.hadoop.yarn.webapp.util.WebAppUtils; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton @Path("/ws/v1/cluster") public class RMWebServices { private static final Log LOG = LogFactory.getLog(RMWebServices.class.getName()); private static final String EMPTY = ""; private static final String ANY = "*"; private final ResourceManager rm; private static RecordFactory recordFactory = RecordFactoryProvider.getRecordFactory(null); private final Configuration conf; private @Context HttpServletResponse response; @VisibleForTesting boolean isCentralizedNodeLabelConfiguration = true; public final static String DELEGATION_TOKEN_HEADER = "Hadoop-YARN-RM-Delegation-Token"; @Inject public RMWebServices(final ResourceManager rm, Configuration conf) { this.rm = rm; this.conf = conf; isCentralizedNodeLabelConfiguration = YarnConfiguration.isCentralizedNodeLabelConfiguration(conf); } RMWebServices(ResourceManager rm, Configuration conf, HttpServletResponse response) { this(rm, conf); this.response = response; } protected Boolean hasAccess(RMApp app, HttpServletRequest hsr) { // Check for the authorization. UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI != null && !(this.rm.getApplicationACLsManager().checkAccess(callerUGI, ApplicationAccessType.VIEW_APP, app.getUser(), app.getApplicationId()) || this.rm.getQueueACLsManager().checkAccess(callerUGI, QueueACL.ADMINISTER_QUEUE, app.getQueue()))) { return false; } return true; } private void init() { //clear content type response.setContentType(null); } @GET @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public ClusterInfo get() { return getClusterInfo(); } @GET @Path("/info") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public ClusterInfo getClusterInfo() { init(); return new ClusterInfo(this.rm); } @GET @Path("/metrics") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public ClusterMetricsInfo getClusterMetricsInfo() { init(); return new ClusterMetricsInfo(this.rm); } @GET @Path("/scheduler") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public SchedulerTypeInfo getSchedulerInfo() { init(); ResourceScheduler rs = rm.getResourceScheduler(); SchedulerInfo sinfo; if (rs instanceof CapacityScheduler) { CapacityScheduler cs = (CapacityScheduler) rs; CSQueue root = cs.getRootQueue(); sinfo = new CapacitySchedulerInfo(root, cs); } else if (rs instanceof FairScheduler) { FairScheduler fs = (FairScheduler) rs; sinfo = new FairSchedulerInfo(fs); } else if (rs instanceof FifoScheduler) { sinfo = new FifoSchedulerInfo(this.rm); } else { throw new NotFoundException("Unknown scheduler configured"); } return new SchedulerTypeInfo(sinfo); } @POST @Path("/scheduler/logs") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public String dumpSchedulerLogs(@FormParam("time") String time, @Context HttpServletRequest hsr) throws IOException { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); ApplicationACLsManager aclsManager = rm.getApplicationACLsManager(); if (aclsManager.areACLsEnabled()) { if (callerUGI == null || !aclsManager.isAdmin(callerUGI)) { String msg = "Only admins can carry out this operation."; throw new ForbiddenException(msg); } } ResourceScheduler rs = rm.getResourceScheduler(); int period = Integer.parseInt(time); if (period <= 0) { throw new BadRequestException("Period must be greater than 0"); } final String logHierarchy = "org.apache.hadoop.yarn.server.resourcemanager.scheduler"; String logfile = "yarn-scheduler-debug.log"; if (rs instanceof CapacityScheduler) { logfile = "yarn-capacity-scheduler-debug.log"; } else if (rs instanceof FairScheduler) { logfile = "yarn-fair-scheduler-debug.log"; } AdHocLogDumper dumper = new AdHocLogDumper(logHierarchy, logfile); // time period is sent to us in seconds dumper.dumpLogs("DEBUG", period * 1000); return "Capacity scheduler logs are being created."; } /** * Returns all nodes in the cluster. If the states param is given, returns * all nodes that are in the comma-separated list of states. */ @GET @Path("/nodes") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public NodesInfo getNodes(@QueryParam("states") String states) { init(); ResourceScheduler sched = this.rm.getResourceScheduler(); if (sched == null) { throw new NotFoundException("Null ResourceScheduler instance"); } EnumSet<NodeState> acceptedStates; if (states == null) { acceptedStates = EnumSet.allOf(NodeState.class); } else { acceptedStates = EnumSet.noneOf(NodeState.class); for (String stateStr : states.split(",")) { acceptedStates.add(NodeState.valueOf(StringUtils.toUpperCase(stateStr))); } } Collection<RMNode> rmNodes = RMServerUtils.queryRMNodes(this.rm.getRMContext(), acceptedStates); NodesInfo nodesInfo = new NodesInfo(); for (RMNode rmNode : rmNodes) { NodeInfo nodeInfo = new NodeInfo(rmNode, sched); if (EnumSet.of(NodeState.LOST, NodeState.DECOMMISSIONED, NodeState.REBOOTED) .contains(rmNode.getState())) { nodeInfo.setNodeHTTPAddress(EMPTY); } nodesInfo.add(nodeInfo); } return nodesInfo; } @GET @Path("/nodes/{nodeId}") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public NodeInfo getNode(@PathParam("nodeId") String nodeId) { init(); if (nodeId == null || nodeId.isEmpty()) { throw new NotFoundException("nodeId, " + nodeId + ", is empty or null"); } ResourceScheduler sched = this.rm.getResourceScheduler(); if (sched == null) { throw new NotFoundException("Null ResourceScheduler instance"); } NodeId nid = NodeId.fromString(nodeId); RMNode ni = this.rm.getRMContext().getRMNodes().get(nid); boolean isInactive = false; if (ni == null) { ni = this.rm.getRMContext().getInactiveRMNodes().get(nid); if (ni == null) { throw new NotFoundException("nodeId, " + nodeId + ", is not found"); } isInactive = true; } NodeInfo nodeInfo = new NodeInfo(ni, sched); if (isInactive) { nodeInfo.setNodeHTTPAddress(EMPTY); } return nodeInfo; } @GET @Path("/apps") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public AppsInfo getApps(@Context HttpServletRequest hsr, @QueryParam("state") String stateQuery, @QueryParam("states") Set<String> statesQuery, @QueryParam("finalStatus") String finalStatusQuery, @QueryParam("user") String userQuery, @QueryParam("queue") String queueQuery, @QueryParam("limit") String count, @QueryParam("startedTimeBegin") String startedBegin, @QueryParam("startedTimeEnd") String startedEnd, @QueryParam("finishedTimeBegin") String finishBegin, @QueryParam("finishedTimeEnd") String finishEnd, @QueryParam("applicationTypes") Set<String> applicationTypes, @QueryParam("applicationTags") Set<String> applicationTags) { boolean checkCount = false; boolean checkStart = false; boolean checkEnd = false; boolean checkAppTypes = false; boolean checkAppStates = false; boolean checkAppTags = false; long countNum = 0; // set values suitable in case both of begin/end not specified long sBegin = 0; long sEnd = Long.MAX_VALUE; long fBegin = 0; long fEnd = Long.MAX_VALUE; init(); if (count != null && !count.isEmpty()) { checkCount = true; countNum = Long.parseLong(count); if (countNum <= 0) { throw new BadRequestException("limit value must be greater then 0"); } } if (startedBegin != null && !startedBegin.isEmpty()) { checkStart = true; sBegin = Long.parseLong(startedBegin); if (sBegin < 0) { throw new BadRequestException("startedTimeBegin must be greater than 0"); } } if (startedEnd != null && !startedEnd.isEmpty()) { checkStart = true; sEnd = Long.parseLong(startedEnd); if (sEnd < 0) { throw new BadRequestException("startedTimeEnd must be greater than 0"); } } if (sBegin > sEnd) { throw new BadRequestException("startedTimeEnd must be greater than startTimeBegin"); } if (finishBegin != null && !finishBegin.isEmpty()) { checkEnd = true; fBegin = Long.parseLong(finishBegin); if (fBegin < 0) { throw new BadRequestException("finishTimeBegin must be greater than 0"); } } if (finishEnd != null && !finishEnd.isEmpty()) { checkEnd = true; fEnd = Long.parseLong(finishEnd); if (fEnd < 0) { throw new BadRequestException("finishTimeEnd must be greater than 0"); } } if (fBegin > fEnd) { throw new BadRequestException("finishTimeEnd must be greater than finishTimeBegin"); } Set<String> appTypes = parseQueries(applicationTypes, false); if (!appTypes.isEmpty()) { checkAppTypes = true; } Set<String> appTags = parseQueries(applicationTags, false); if (!appTags.isEmpty()) { checkAppTags = true; } // stateQuery is deprecated. if (stateQuery != null && !stateQuery.isEmpty()) { statesQuery.add(stateQuery); } Set<String> appStates = parseQueries(statesQuery, true); if (!appStates.isEmpty()) { checkAppStates = true; } GetApplicationsRequest request = GetApplicationsRequest.newInstance(); if (checkStart) { request.setStartRange(sBegin, sEnd); } if (checkEnd) { request.setFinishRange(fBegin, fEnd); } if (checkCount) { request.setLimit(countNum); } if (checkAppTypes) { request.setApplicationTypes(appTypes); } if (checkAppTags) { request.setApplicationTags(appTags); } if (checkAppStates) { request.setApplicationStates(appStates); } if (queueQuery != null && !queueQuery.isEmpty()) { ResourceScheduler rs = rm.getResourceScheduler(); if (rs instanceof CapacityScheduler) { CapacityScheduler cs = (CapacityScheduler) rs; // validate queue exists try { cs.getQueueInfo(queueQuery, false, false); } catch (IOException e) { throw new BadRequestException(e.getMessage()); } } Set<String> queues = new HashSet<String>(1); queues.add(queueQuery); request.setQueues(queues); } if (userQuery != null && !userQuery.isEmpty()) { Set<String> users = new HashSet<String>(1); users.add(userQuery); request.setUsers(users); } List<ApplicationReport> appReports = null; try { appReports = rm.getClientRMService().getApplications(request, false).getApplicationList(); } catch (YarnException e) { LOG.error("Unable to retrieve apps from ClientRMService", e); throw new YarnRuntimeException("Unable to retrieve apps from ClientRMService", e); } final ConcurrentMap<ApplicationId, RMApp> apps = rm.getRMContext().getRMApps(); AppsInfo allApps = new AppsInfo(); for (ApplicationReport report : appReports) { RMApp rmapp = apps.get(report.getApplicationId()); if (rmapp == null) { continue; } if (finalStatusQuery != null && !finalStatusQuery.isEmpty()) { FinalApplicationStatus.valueOf(finalStatusQuery); if (!rmapp.getFinalApplicationStatus().toString().equalsIgnoreCase(finalStatusQuery)) { continue; } } AppInfo app = new AppInfo(rm, rmapp, hasAccess(rmapp, hsr), WebAppUtils.getHttpSchemePrefix(conf)); allApps.add(app); } return allApps; } @GET @Path("/appstatistics") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public ApplicationStatisticsInfo getAppStatistics(@Context HttpServletRequest hsr, @QueryParam("states") Set<String> stateQueries, @QueryParam("applicationTypes") Set<String> typeQueries) { init(); // parse the params and build the scoreboard // converting state/type name to lowercase Set<String> states = parseQueries(stateQueries, true); Set<String> types = parseQueries(typeQueries, false); // if no types, counts the applications of any types if (types.size() == 0) { types.add(ANY); } else if (types.size() != 1) { throw new BadRequestException("# of applicationTypes = " + types.size() + ", we temporarily support at most one applicationType"); } // if no states, returns the counts of all RMAppStates if (states.size() == 0) { for (YarnApplicationState state : YarnApplicationState.values()) { states.add(StringUtils.toLowerCase(state.toString())); } } // in case we extend to multiple applicationTypes in the future Map<YarnApplicationState, Map<String, Long>> scoreboard = buildScoreboard(states, types); // go through the apps in RM to count the numbers, ignoring the case of // the state/type name ConcurrentMap<ApplicationId, RMApp> apps = rm.getRMContext().getRMApps(); for (RMApp rmapp : apps.values()) { YarnApplicationState state = rmapp.createApplicationState(); String type = StringUtils.toLowerCase(rmapp.getApplicationType().trim()); if (states.contains(StringUtils.toLowerCase(state.toString()))) { if (types.contains(ANY)) { countApp(scoreboard, state, ANY); } else if (types.contains(type)) { countApp(scoreboard, state, type); } } } // fill the response object ApplicationStatisticsInfo appStatInfo = new ApplicationStatisticsInfo(); for (Map.Entry<YarnApplicationState, Map<String, Long>> partScoreboard : scoreboard.entrySet()) { for (Map.Entry<String, Long> statEntry : partScoreboard.getValue().entrySet()) { StatisticsItemInfo statItem = new StatisticsItemInfo(partScoreboard.getKey(), statEntry.getKey(), statEntry.getValue()); appStatInfo.add(statItem); } } return appStatInfo; } private static Set<String> parseQueries(Set<String> queries, boolean isState) { Set<String> params = new HashSet<String>(); if (!queries.isEmpty()) { for (String query : queries) { if (query != null && !query.trim().isEmpty()) { String[] paramStrs = query.split(","); for (String paramStr : paramStrs) { if (paramStr != null && !paramStr.trim().isEmpty()) { if (isState) { try { // enum string is in the uppercase YarnApplicationState.valueOf(StringUtils.toUpperCase(paramStr.trim())); } catch (RuntimeException e) { YarnApplicationState[] stateArray = YarnApplicationState.values(); String allAppStates = Arrays.toString(stateArray); throw new BadRequestException("Invalid application-state " + paramStr.trim() + " specified. It should be one of " + allAppStates); } } params.add(StringUtils.toLowerCase(paramStr.trim())); } } } } } return params; } private static Map<YarnApplicationState, Map<String, Long>> buildScoreboard(Set<String> states, Set<String> types) { Map<YarnApplicationState, Map<String, Long>> scoreboard = new HashMap<YarnApplicationState, Map<String, Long>>(); // default states will result in enumerating all YarnApplicationStates assert !states.isEmpty(); for (String state : states) { Map<String, Long> partScoreboard = new HashMap<String, Long>(); scoreboard.put(YarnApplicationState.valueOf(StringUtils.toUpperCase(state)), partScoreboard); // types is verified no to be empty for (String type : types) { partScoreboard.put(type, 0L); } } return scoreboard; } private static void countApp(Map<YarnApplicationState, Map<String, Long>> scoreboard, YarnApplicationState state, String type) { Map<String, Long> partScoreboard = scoreboard.get(state); Long count = partScoreboard.get(type); partScoreboard.put(type, count + 1L); } @GET @Path("/apps/{appid}") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public AppInfo getApp(@Context HttpServletRequest hsr, @PathParam("appid") String appId) { init(); ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId); RMApp app = rm.getRMContext().getRMApps().get(id); if (app == null) { throw new NotFoundException("app with id: " + appId + " not found"); } return new AppInfo(rm, app, hasAccess(app, hsr), hsr.getScheme() + "://"); } @GET @Path("/apps/{appid}/appattempts") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public AppAttemptsInfo getAppAttempts(@Context HttpServletRequest hsr, @PathParam("appid") String appId) { init(); ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId); RMApp app = rm.getRMContext().getRMApps().get(id); if (app == null) { throw new NotFoundException("app with id: " + appId + " not found"); } AppAttemptsInfo appAttemptsInfo = new AppAttemptsInfo(); for (RMAppAttempt attempt : app.getAppAttempts().values()) { AppAttemptInfo attemptInfo = new AppAttemptInfo(rm, attempt, app.getUser(), hsr.getScheme() + "://"); appAttemptsInfo.add(attemptInfo); } return appAttemptsInfo; } @GET @Path("/apps/{appid}/state") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public AppState getAppState(@Context HttpServletRequest hsr, @PathParam("appid") String appId) throws AuthorizationException { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); String userName = ""; if (callerUGI != null) { userName = callerUGI.getUserName(); } RMApp app = null; try { app = getRMAppForAppId(appId); } catch (NotFoundException e) { RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_STATE, "UNKNOWN", "RMWebService", "Trying to get state of an absent application " + appId); throw e; } AppState ret = new AppState(); ret.setState(app.getState().toString()); return ret; } // can't return POJO because we can't control the status code // it's always set to 200 when we need to allow it to be set // to 202 @PUT @Path("/apps/{appid}/state") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response updateAppState(AppState targetState, @Context HttpServletRequest hsr, @PathParam("appid") String appId) throws AuthorizationException, YarnException, InterruptedException, IOException { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated"; throw new AuthorizationException(msg); } if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } String userName = callerUGI.getUserName(); RMApp app = null; try { app = getRMAppForAppId(appId); } catch (NotFoundException e) { RMAuditLogger.logFailure(userName, AuditConstants.KILL_APP_REQUEST, "UNKNOWN", "RMWebService", "Trying to kill an absent application " + appId); throw e; } if (!app.getState().toString().equals(targetState.getState())) { // user is attempting to change state. right we only // allow users to kill the app if (targetState.getState().equals(YarnApplicationState.KILLED.toString())) { return killApp(app, callerUGI, hsr, targetState.getDiagnostics()); } throw new BadRequestException( "Only '" + YarnApplicationState.KILLED.toString() + "' is allowed as a target state."); } AppState ret = new AppState(); ret.setState(app.getState().toString()); return Response.status(Status.OK).entity(ret).build(); } @GET @Path("/get-node-to-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public NodeToLabelsInfo getNodeToLabels(@Context HttpServletRequest hsr) throws IOException { init(); NodeToLabelsInfo ntl = new NodeToLabelsInfo(); HashMap<String, NodeLabelsInfo> ntlMap = ntl.getNodeToLabels(); Map<NodeId, Set<NodeLabel>> nodeIdToLabels = rm.getRMContext().getNodeLabelManager().getNodeLabelsInfo(); for (Map.Entry<NodeId, Set<NodeLabel>> nitle : nodeIdToLabels.entrySet()) { List<NodeLabel> labels = new ArrayList<NodeLabel>(nitle.getValue()); ntlMap.put(nitle.getKey().toString(), new NodeLabelsInfo(labels)); } return ntl; } @GET @Path("/label-mappings") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public LabelsToNodesInfo getLabelsToNodes(@QueryParam("labels") Set<String> labels) throws IOException { init(); LabelsToNodesInfo lts = new LabelsToNodesInfo(); Map<NodeLabelInfo, NodeIDsInfo> ltsMap = lts.getLabelsToNodes(); Map<NodeLabel, Set<NodeId>> labelsToNodeId = null; if (labels == null || labels.size() == 0) { labelsToNodeId = rm.getRMContext().getNodeLabelManager().getLabelsInfoToNodes(); } else { labelsToNodeId = rm.getRMContext().getNodeLabelManager().getLabelsInfoToNodes(labels); } for (Entry<NodeLabel, Set<NodeId>> entry : labelsToNodeId.entrySet()) { List<String> nodeIdStrList = new ArrayList<String>(); for (NodeId nodeId : entry.getValue()) { nodeIdStrList.add(nodeId.toString()); } ltsMap.put(new NodeLabelInfo(entry.getKey()), new NodeIDsInfo(nodeIdStrList)); } return lts; } @POST @Path("/replace-node-to-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response replaceLabelsOnNodes(final NodeToLabelsEntryList newNodeToLabels, @Context HttpServletRequest hsr) throws IOException { Map<NodeId, Set<String>> nodeIdToLabels = new HashMap<NodeId, Set<String>>(); for (NodeToLabelsEntry nitle : newNodeToLabels.getNodeToLabels()) { nodeIdToLabels.put(ConverterUtils.toNodeIdWithDefaultPort(nitle.getNodeId()), new HashSet<String>(nitle.getNodeLabels())); } return replaceLabelsOnNode(nodeIdToLabels, hsr, "/replace-node-to-labels"); } @POST @Path("/nodes/{nodeId}/replace-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response replaceLabelsOnNode(@QueryParam("labels") Set<String> newNodeLabelsName, @Context HttpServletRequest hsr, @PathParam("nodeId") String nodeId) throws Exception { NodeId nid = ConverterUtils.toNodeIdWithDefaultPort(nodeId); Map<NodeId, Set<String>> newLabelsForNode = new HashMap<NodeId, Set<String>>(); newLabelsForNode.put(nid, new HashSet<String>(newNodeLabelsName)); return replaceLabelsOnNode(newLabelsForNode, hsr, "/nodes/nodeid/replace-labels"); } private Response replaceLabelsOnNode(Map<NodeId, Set<String>> newLabelsForNode, HttpServletRequest hsr, String operation) throws IOException { init(); NodeLabelsUtils.verifyCentralizedNodeLabelConfEnabled("replaceLabelsOnNode", isCentralizedNodeLabelConfiguration); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated for" + " post to ..." + operation; throw new AuthorizationException(msg); } if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) { String msg = "User " + callerUGI.getShortUserName() + " not authorized" + " for post to ..." + operation; throw new AuthorizationException(msg); } try { rm.getRMContext().getNodeLabelManager().replaceLabelsOnNode(newLabelsForNode); } catch (IOException e) { throw new BadRequestException(e); } return Response.status(Status.OK).build(); } @GET @Path("/get-node-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public NodeLabelsInfo getClusterNodeLabels(@Context HttpServletRequest hsr) throws IOException { init(); List<NodeLabel> nodeLabels = rm.getRMContext().getNodeLabelManager().getClusterNodeLabels(); NodeLabelsInfo ret = new NodeLabelsInfo(nodeLabels); return ret; } @POST @Path("/add-node-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response addToClusterNodeLabels(final NodeLabelsInfo newNodeLabels, @Context HttpServletRequest hsr) throws Exception { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated for" + " post to .../add-node-labels"; throw new AuthorizationException(msg); } if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) { String msg = "User " + callerUGI.getShortUserName() + " not authorized" + " for post to .../add-node-labels "; throw new AuthorizationException(msg); } try { rm.getRMContext().getNodeLabelManager().addToCluserNodeLabels(newNodeLabels.getNodeLabels()); } catch (IOException e) { throw new BadRequestException(e); } return Response.status(Status.OK).build(); } @POST @Path("/remove-node-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response removeFromCluserNodeLabels(@QueryParam("labels") Set<String> oldNodeLabels, @Context HttpServletRequest hsr) throws Exception { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated for" + " post to .../remove-node-labels"; throw new AuthorizationException(msg); } if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) { String msg = "User " + callerUGI.getShortUserName() + " not authorized" + " for post to .../remove-node-labels "; throw new AuthorizationException(msg); } try { rm.getRMContext().getNodeLabelManager().removeFromClusterNodeLabels(new HashSet<String>(oldNodeLabels)); } catch (IOException e) { throw new BadRequestException(e); } return Response.status(Status.OK).build(); } @GET @Path("/nodes/{nodeId}/get-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public NodeLabelsInfo getLabelsOnNode(@Context HttpServletRequest hsr, @PathParam("nodeId") String nodeId) throws IOException { init(); NodeId nid = ConverterUtils.toNodeIdWithDefaultPort(nodeId); List<NodeLabel> labels = new ArrayList<NodeLabel>( rm.getRMContext().getNodeLabelManager().getLabelsInfoByNode(nid)); return new NodeLabelsInfo(labels); } protected Response killApp(RMApp app, UserGroupInformation callerUGI, HttpServletRequest hsr, final String diagnostic) throws IOException, InterruptedException { if (app == null) { throw new IllegalArgumentException("app cannot be null"); } String userName = callerUGI.getUserName(); final ApplicationId appid = app.getApplicationId(); KillApplicationResponse resp = null; try { resp = callerUGI.doAs(new PrivilegedExceptionAction<KillApplicationResponse>() { @Override public KillApplicationResponse run() throws IOException, YarnException { KillApplicationRequest req = KillApplicationRequest.newInstance(appid); if (diagnostic != null) { req.setDiagnostics(diagnostic); } return rm.getClientRMService().forceKillApplication(req); } }); } 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 kill appid " + appId + " by remote user " + userName; return Response.status(Status.FORBIDDEN).entity(msg).build(); } else { throw ue; } } else { throw ue; } } AppState ret = new AppState(); ret.setState(app.getState().toString()); if (resp.getIsKillCompleted()) { RMAuditLogger.logSuccess(userName, AuditConstants.KILL_APP_REQUEST, "RMWebService", app.getApplicationId()); } else { return Response.status(Status.ACCEPTED).entity(ret).header(HttpHeaders.LOCATION, hsr.getRequestURL()) .build(); } return Response.status(Status.OK).entity(ret).build(); } @GET @Path("/apps/{appid}/priority") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public AppPriority getAppPriority(@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_PRIORITY, "UNKNOWN", "RMWebService", "Trying to get priority of an absent application " + appId); throw e; } AppPriority ret = new AppPriority(); ret.setPriority(app.getApplicationSubmissionContext().getPriority().getPriority()); return ret; } @PUT @Path("/apps/{appid}/priority") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response updateApplicationPriority(AppPriority targetPriority, @Context HttpServletRequest hsr, @PathParam("appid") String appId) throws AuthorizationException, YarnException, InterruptedException, IOException { init(); if (targetPriority == null) { throw new YarnException("Target Priority 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_PRIORITY, "UNKNOWN", "RMWebService", "Trying to update priority an absent application " + appId); throw e; } Priority priority = app.getApplicationSubmissionContext().getPriority(); if (priority == null || priority.getPriority() != targetPriority.getPriority()) { return modifyApplicationPriority(app, callerUGI, targetPriority.getPriority()); } return Response.status(Status.OK).entity(targetPriority).build(); } private Response modifyApplicationPriority(final RMApp app, UserGroupInformation callerUGI, final int appPriority) throws IOException, InterruptedException { String userName = callerUGI.getUserName(); try { callerUGI.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws IOException, YarnException { Priority priority = Priority.newInstance(appPriority); UpdateApplicationPriorityRequest request = UpdateApplicationPriorityRequest .newInstance(app.getApplicationId(), priority); rm.getClientRMService().updateApplicationPriority(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 if (ye.getMessage().startsWith("Application in") && ye.getMessage().endsWith("state cannot be update priority.")) { return Response.status(Status.BAD_REQUEST).entity(ye.getMessage()).build(); } else { throw ue; } } else { throw ue; } } AppPriority ret = new AppPriority(app.getApplicationSubmissionContext().getPriority().getPriority()); return Response.status(Status.OK).entity(ret).build(); } @GET @Path("/apps/{appid}/queue") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public AppQueue getAppQueue(@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_QUEUE, "UNKNOWN", "RMWebService", "Trying to get queue of an absent application " + appId); throw e; } AppQueue ret = new AppQueue(); ret.setQueue(app.getQueue()); return ret; } @PUT @Path("/apps/{appid}/queue") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response updateAppQueue(AppQueue targetQueue, @Context HttpServletRequest hsr, @PathParam("appid") String appId) throws AuthorizationException, YarnException, InterruptedException, IOException { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated"; throw new AuthorizationException(msg); } if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } String userName = callerUGI.getUserName(); RMApp app = null; try { app = getRMAppForAppId(appId); } catch (NotFoundException e) { RMAuditLogger.logFailure(userName, AuditConstants.MOVE_APP_REQUEST, "UNKNOWN", "RMWebService", "Trying to move an absent application " + appId); throw e; } if (!app.getQueue().equals(targetQueue.getQueue())) { // user is attempting to change queue. return moveApp(app, callerUGI, targetQueue.getQueue()); } AppQueue ret = new AppQueue(); ret.setQueue(app.getQueue()); return Response.status(Status.OK).entity(ret).build(); } protected Response moveApp(RMApp app, UserGroupInformation callerUGI, String targetQueue) throws IOException, InterruptedException { if (app == null) { throw new IllegalArgumentException("app cannot be null"); } String userName = callerUGI.getUserName(); final ApplicationId appid = app.getApplicationId(); final String reqTargetQueue = targetQueue; try { callerUGI.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws IOException, YarnException { MoveApplicationAcrossQueuesRequest req = MoveApplicationAcrossQueuesRequest.newInstance(appid, reqTargetQueue); rm.getClientRMService().moveApplicationAcrossQueues(req); 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 move appid " + appId + " by remote user " + userName; return Response.status(Status.FORBIDDEN).entity(msg).build(); } else if (ye.getMessage().startsWith("App in") && ye.getMessage().endsWith("state cannot be moved.")) { return Response.status(Status.BAD_REQUEST).entity(ye.getMessage()).build(); } else { throw ue; } } else { throw ue; } } AppQueue ret = new AppQueue(); ret.setQueue(app.getQueue()); return Response.status(Status.OK).entity(ret).build(); } private RMApp getRMAppForAppId(String appId) { ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId); RMApp app = rm.getRMContext().getRMApps().get(id); if (app == null) { throw new NotFoundException("app with id: " + appId + " not found"); } return app; } private UserGroupInformation getCallerUserGroupInformation(HttpServletRequest hsr, boolean usePrincipal) { String remoteUser = hsr.getRemoteUser(); if (usePrincipal) { Principal princ = hsr.getUserPrincipal(); remoteUser = princ == null ? null : princ.getName(); } UserGroupInformation callerUGI = null; if (remoteUser != null) { callerUGI = UserGroupInformation.createRemoteUser(remoteUser); } return callerUGI; } private boolean isStaticUser(UserGroupInformation callerUGI) { String staticUser = conf.get(CommonConfigurationKeys.HADOOP_HTTP_STATIC_USER, CommonConfigurationKeys.DEFAULT_HADOOP_HTTP_STATIC_USER); return staticUser.equals(callerUGI.getUserName()); } /** * Generates a new ApplicationId which is then sent to the client * * @param hsr * the servlet request * @return Response containing the app id and the maximum resource * capabilities * @throws AuthorizationException * @throws IOException * @throws InterruptedException */ @POST @Path("/apps/new-application") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response createNewApplication(@Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException { 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)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } NewApplication appId = createNewApplication(); return Response.status(Status.OK).entity(appId).build(); } // reuse the code in ClientRMService to create new app // get the new app id and submit app // set location header with new app location /** * Function to submit an app to the RM * * @param newApp * structure containing information to construct the * ApplicationSubmissionContext * @param hsr * the servlet request * @return Response containing the status code * @throws AuthorizationException * @throws IOException * @throws InterruptedException */ @POST @Path("/apps") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response submitApplication(ApplicationSubmissionContextInfo newApp, @Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException { 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)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } ApplicationSubmissionContext appContext = createAppSubmissionContext(newApp); final SubmitApplicationRequest req = SubmitApplicationRequest.newInstance(appContext); try { callerUGI.doAs(new PrivilegedExceptionAction<SubmitApplicationResponse>() { @Override public SubmitApplicationResponse run() throws IOException, YarnException { return rm.getClientRMService().submitApplication(req); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { throw new BadRequestException(ue.getCause().getMessage()); } LOG.info("Submit app request failed", ue); throw ue; } String url = hsr.getRequestURL() + "/" + newApp.getApplicationId(); return Response.status(Status.ACCEPTED).header(HttpHeaders.LOCATION, url).build(); } /** * Function that actually creates the ApplicationId by calling the * ClientRMService * * @return returns structure containing the app-id and maximum resource * capabilities */ private NewApplication createNewApplication() { GetNewApplicationRequest req = recordFactory.newRecordInstance(GetNewApplicationRequest.class); GetNewApplicationResponse resp; try { resp = rm.getClientRMService().getNewApplication(req); } catch (YarnException e) { String msg = "Unable to create new app from RM web service"; LOG.error(msg, e); throw new YarnRuntimeException(msg, e); } NewApplication appId = new NewApplication(resp.getApplicationId().toString(), new ResourceInfo(resp.getMaximumResourceCapability())); return appId; } /** * Create the actual ApplicationSubmissionContext to be submitted to the RM * from the information provided by the user. * * @param newApp * the information provided by the user * @return returns the constructed ApplicationSubmissionContext * @throws IOException */ protected ApplicationSubmissionContext createAppSubmissionContext(ApplicationSubmissionContextInfo newApp) throws IOException { // create local resources and app submission context ApplicationId appid; String error = "Could not parse application id " + newApp.getApplicationId(); try { appid = ApplicationId.fromString(newApp.getApplicationId()); } catch (Exception e) { throw new BadRequestException(error); } ApplicationSubmissionContext appContext = ApplicationSubmissionContext.newInstance(appid, newApp.getApplicationName(), newApp.getQueue(), Priority.newInstance(newApp.getPriority()), createContainerLaunchContext(newApp), newApp.getUnmanagedAM(), newApp.getCancelTokensWhenComplete(), newApp.getMaxAppAttempts(), createAppSubmissionContextResource(newApp), newApp.getApplicationType(), newApp.getKeepContainersAcrossApplicationAttempts(), newApp.getAppNodeLabelExpression(), newApp.getAMContainerNodeLabelExpression()); appContext.setApplicationTags(newApp.getApplicationTags()); return appContext; } protected Resource createAppSubmissionContextResource(ApplicationSubmissionContextInfo newApp) throws BadRequestException { if (newApp.getResource().getvCores() > rm.getConfig().getInt( YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES, YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES)) { String msg = "Requested more cores than configured max"; throw new BadRequestException(msg); } if (newApp.getResource().getMemorySize() > rm.getConfig().getInt( YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_MB, YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_MB)) { String msg = "Requested more memory than configured max"; throw new BadRequestException(msg); } if (newApp.getResource().getGpus() > rm.getConfig().getInt( YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_GPUS, YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_GPUS)) { String msg = "Requested more gpus than configured max"; throw new BadRequestException(msg); } Resource r = Resource.newInstance(newApp.getResource().getMemorySize(), newApp.getResource().getvCores()); return r; } /** * Create the ContainerLaunchContext required for the * ApplicationSubmissionContext. This function takes the user information and * generates the ByteBuffer structures required by the ContainerLaunchContext * * @param newApp * the information provided by the user * @return created context * @throws BadRequestException * @throws IOException */ protected ContainerLaunchContext createContainerLaunchContext(ApplicationSubmissionContextInfo newApp) throws BadRequestException, IOException { // create container launch context HashMap<String, ByteBuffer> hmap = new HashMap<String, ByteBuffer>(); for (Map.Entry<String, String> entry : newApp.getContainerLaunchContextInfo().getAuxillaryServiceData() .entrySet()) { if (entry.getValue().isEmpty() == false) { Base64 decoder = new Base64(0, null, true); byte[] data = decoder.decode(entry.getValue()); hmap.put(entry.getKey(), ByteBuffer.wrap(data)); } } HashMap<String, LocalResource> hlr = new HashMap<String, LocalResource>(); for (Map.Entry<String, LocalResourceInfo> entry : newApp.getContainerLaunchContextInfo().getResources() .entrySet()) { LocalResourceInfo l = entry.getValue(); LocalResource lr = LocalResource.newInstance(URL.fromURI(l.getUrl()), l.getType(), l.getVisibility(), l.getSize(), l.getTimestamp()); hlr.put(entry.getKey(), lr); } DataOutputBuffer out = new DataOutputBuffer(); Credentials cs = createCredentials(newApp.getContainerLaunchContextInfo().getCredentials()); cs.writeTokenStorageToStream(out); ByteBuffer tokens = ByteBuffer.wrap(out.getData()); ContainerLaunchContext ctx = ContainerLaunchContext.newInstance(hlr, newApp.getContainerLaunchContextInfo().getEnvironment(), newApp.getContainerLaunchContextInfo().getCommands(), hmap, tokens, newApp.getContainerLaunchContextInfo().getAcls()); return ctx; } /** * Generate a Credentials object from the information in the CredentialsInfo * object. * * @param credentials * the CredentialsInfo provided by the user. * @return */ private Credentials createCredentials(CredentialsInfo credentials) { Credentials ret = new Credentials(); try { for (Map.Entry<String, String> entry : credentials.getTokens().entrySet()) { Text alias = new Text(entry.getKey()); Token<TokenIdentifier> token = new Token<TokenIdentifier>(); token.decodeFromUrlString(entry.getValue()); ret.addToken(alias, token); } for (Map.Entry<String, String> entry : credentials.getSecrets().entrySet()) { Text alias = new Text(entry.getKey()); Base64 decoder = new Base64(0, null, true); byte[] secret = decoder.decode(entry.getValue()); ret.addSecretKey(alias, secret); } } catch (IOException ie) { throw new BadRequestException( "Could not parse credentials data; exception message = " + ie.getMessage()); } return ret; } private UserGroupInformation createKerberosUserGroupInformation(HttpServletRequest hsr) throws AuthorizationException, YarnException { UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated"; throw new AuthorizationException(msg); } String authType = hsr.getAuthType(); if (!KerberosAuthenticationHandler.TYPE.equalsIgnoreCase(authType)) { String msg = "Delegation token operations can only be carried out on a " + "Kerberos authenticated channel. Expected auth type is " + KerberosAuthenticationHandler.TYPE + ", got type " + authType; throw new YarnException(msg); } if (hsr.getAttribute(DelegationTokenAuthenticationHandler.DELEGATION_TOKEN_UGI_ATTRIBUTE) != null) { String msg = "Delegation token operations cannot be carried out using delegation" + " token authentication."; throw new YarnException(msg); } callerUGI.setAuthenticationMethod(AuthenticationMethod.KERBEROS); return callerUGI; } @POST @Path("/delegation-token") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response postDelegationToken(DelegationToken tokenData, @Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException, Exception { init(); UserGroupInformation callerUGI; try { callerUGI = createKerberosUserGroupInformation(hsr); } catch (YarnException ye) { return Response.status(Status.FORBIDDEN).entity(ye.getMessage()).build(); } return createDelegationToken(tokenData, hsr, callerUGI); } @POST @Path("/delegation-token/expiration") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response postDelegationTokenExpiration(@Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException, Exception { init(); UserGroupInformation callerUGI; try { callerUGI = createKerberosUserGroupInformation(hsr); } catch (YarnException ye) { return Response.status(Status.FORBIDDEN).entity(ye.getMessage()).build(); } DelegationToken requestToken = new DelegationToken(); requestToken.setToken(extractToken(hsr).encodeToUrlString()); return renewDelegationToken(requestToken, hsr, callerUGI); } private Response createDelegationToken(DelegationToken tokenData, HttpServletRequest hsr, UserGroupInformation callerUGI) throws AuthorizationException, IOException, InterruptedException, Exception { final String renewer = tokenData.getRenewer(); GetDelegationTokenResponse resp; try { resp = callerUGI.doAs(new PrivilegedExceptionAction<GetDelegationTokenResponse>() { @Override public GetDelegationTokenResponse run() throws IOException, YarnException { GetDelegationTokenRequest createReq = GetDelegationTokenRequest.newInstance(renewer); return rm.getClientRMService().getDelegationToken(createReq); } }); } catch (Exception e) { LOG.info("Create delegation token request failed", e); throw e; } Token<RMDelegationTokenIdentifier> tk = new Token<RMDelegationTokenIdentifier>( resp.getRMDelegationToken().getIdentifier().array(), resp.getRMDelegationToken().getPassword().array(), new Text(resp.getRMDelegationToken().getKind()), new Text(resp.getRMDelegationToken().getService())); RMDelegationTokenIdentifier identifier = tk.decodeIdentifier(); long currentExpiration = rm.getRMContext().getRMDelegationTokenSecretManager().getRenewDate(identifier); DelegationToken respToken = new DelegationToken(tk.encodeToUrlString(), renewer, identifier.getOwner().toString(), tk.getKind().toString(), currentExpiration, identifier.getMaxDate()); return Response.status(Status.OK).entity(respToken).build(); } private Response renewDelegationToken(DelegationToken tokenData, HttpServletRequest hsr, UserGroupInformation callerUGI) throws AuthorizationException, IOException, InterruptedException, Exception { Token<RMDelegationTokenIdentifier> token = extractToken(tokenData.getToken()); org.apache.hadoop.yarn.api.records.Token dToken = BuilderUtils.newDelegationToken(token.getIdentifier(), token.getKind().toString(), token.getPassword(), token.getService().toString()); final RenewDelegationTokenRequest req = RenewDelegationTokenRequest.newInstance(dToken); RenewDelegationTokenResponse resp; try { resp = callerUGI.doAs(new PrivilegedExceptionAction<RenewDelegationTokenResponse>() { @Override public RenewDelegationTokenResponse run() throws IOException, YarnException { return rm.getClientRMService().renewDelegationToken(req); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { if (ue.getCause().getCause() instanceof InvalidToken) { throw new BadRequestException(ue.getCause().getCause().getMessage()); } else if (ue.getCause().getCause() instanceof org.apache.hadoop.security.AccessControlException) { return Response.status(Status.FORBIDDEN).entity(ue.getCause().getCause().getMessage()).build(); } LOG.info("Renew delegation token request failed", ue); throw ue; } LOG.info("Renew delegation token request failed", ue); throw ue; } catch (Exception e) { LOG.info("Renew delegation token request failed", e); throw e; } long renewTime = resp.getNextExpirationTime(); DelegationToken respToken = new DelegationToken(); respToken.setNextExpirationTime(renewTime); return Response.status(Status.OK).entity(respToken).build(); } // For cancelling tokens, the encoded token is passed as a header // There are two reasons for this - // 1. Passing a request body as part of a DELETE request is not // allowed by Jetty // 2. Passing the encoded token as part of the url is not ideal // since urls tend to get logged and anyone with access to // the logs can extract tokens which are meant to be secret @DELETE @Path("/delegation-token") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response cancelDelegationToken(@Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException, Exception { init(); UserGroupInformation callerUGI; try { callerUGI = createKerberosUserGroupInformation(hsr); } catch (YarnException ye) { return Response.status(Status.FORBIDDEN).entity(ye.getMessage()).build(); } Token<RMDelegationTokenIdentifier> token = extractToken(hsr); org.apache.hadoop.yarn.api.records.Token dToken = BuilderUtils.newDelegationToken(token.getIdentifier(), token.getKind().toString(), token.getPassword(), token.getService().toString()); final CancelDelegationTokenRequest req = CancelDelegationTokenRequest.newInstance(dToken); try { callerUGI.doAs(new PrivilegedExceptionAction<CancelDelegationTokenResponse>() { @Override public CancelDelegationTokenResponse run() throws IOException, YarnException { return rm.getClientRMService().cancelDelegationToken(req); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { if (ue.getCause().getCause() instanceof InvalidToken) { throw new BadRequestException(ue.getCause().getCause().getMessage()); } else if (ue.getCause().getCause() instanceof org.apache.hadoop.security.AccessControlException) { return Response.status(Status.FORBIDDEN).entity(ue.getCause().getCause().getMessage()).build(); } LOG.info("Renew delegation token request failed", ue); throw ue; } LOG.info("Renew delegation token request failed", ue); throw ue; } catch (Exception e) { LOG.info("Renew delegation token request failed", e); throw e; } return Response.status(Status.OK).build(); } private Token<RMDelegationTokenIdentifier> extractToken(HttpServletRequest request) { String encodedToken = request.getHeader(DELEGATION_TOKEN_HEADER); if (encodedToken == null) { String msg = "Header '" + DELEGATION_TOKEN_HEADER + "' containing encoded token not found"; throw new BadRequestException(msg); } return extractToken(encodedToken); } private Token<RMDelegationTokenIdentifier> extractToken(String encodedToken) { Token<RMDelegationTokenIdentifier> token = new Token<RMDelegationTokenIdentifier>(); try { token.decodeFromUrlString(encodedToken); } catch (Exception ie) { String msg = "Could not decode encoded token"; throw new BadRequestException(msg); } return token; } /** * Generates a new ReservationId which is then sent to the client. * * @param hsr the servlet request * @return Response containing the app id and the maximum resource * capabilities * @throws AuthorizationException if the user is not authorized * to invoke this method. * @throws IOException if creation fails. * @throws InterruptedException if interrupted. */ @POST @Path("/reservation/new-reservation") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response createNewReservation(@Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException { 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)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } NewReservation reservationId = createNewReservation(); return Response.status(Status.OK).entity(reservationId).build(); } /** * Function that actually creates the {@link ReservationId} by calling the * ClientRMService. * * @return returns structure containing the {@link ReservationId} * @throws IOException if creation fails. */ private NewReservation createNewReservation() throws IOException { GetNewReservationRequest req = recordFactory.newRecordInstance(GetNewReservationRequest.class); GetNewReservationResponse resp; try { resp = rm.getClientRMService().getNewReservation(req); } catch (YarnException e) { String msg = "Unable to create new reservation from RM web service"; LOG.error(msg, e); throw new YarnRuntimeException(msg, e); } NewReservation reservationId = new NewReservation(resp.getReservationId().toString()); return reservationId; } /** * Function to submit a Reservation to the RM. * * @param resContext provides information to construct the * ReservationSubmissionRequest * @param hsr the servlet request * @return Response containing the status code * @throws AuthorizationException * @throws IOException * @throws InterruptedException */ @POST @Path("/reservation/submit") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response submitReservation(ReservationSubmissionRequestInfo resContext, @Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException { 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)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } final ReservationSubmissionRequest reservation = createReservationSubmissionRequest(resContext); try { callerUGI.doAs(new PrivilegedExceptionAction<ReservationSubmissionResponse>() { @Override public ReservationSubmissionResponse run() throws IOException, YarnException { return rm.getClientRMService().submitReservation(reservation); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { throw new BadRequestException(ue.getCause().getMessage()); } LOG.info("Submit reservation request failed", ue); throw ue; } return Response.status(Status.ACCEPTED).build(); } private ReservationSubmissionRequest createReservationSubmissionRequest( ReservationSubmissionRequestInfo resContext) throws IOException { // defending against a couple of common submission format problems if (resContext == null) { throw new BadRequestException("Input ReservationSubmissionContext should not be null"); } ReservationDefinitionInfo resInfo = resContext.getReservationDefinition(); if (resInfo == null) { throw new BadRequestException("Input ReservationDefinition should not be null"); } ReservationRequestsInfo resReqsInfo = resInfo.getReservationRequests(); if (resReqsInfo == null || resReqsInfo.getReservationRequest() == null || resReqsInfo.getReservationRequest().size() == 0) { throw new BadRequestException( "The ReservationDefinition should" + " contain at least one ReservationRequest"); } ReservationRequestInterpreter[] values = ReservationRequestInterpreter.values(); ReservationRequestInterpreter resInt = values[resReqsInfo.getReservationRequestsInterpreter()]; List<ReservationRequest> list = new ArrayList<ReservationRequest>(); for (ReservationRequestInfo resReqInfo : resReqsInfo.getReservationRequest()) { ResourceInfo rInfo = resReqInfo.getCapability(); Resource capability = Resource.newInstance(rInfo.getMemorySize(), rInfo.getvCores()); int numContainers = resReqInfo.getNumContainers(); int minConcurrency = resReqInfo.getMinConcurrency(); long duration = resReqInfo.getDuration(); ReservationRequest rr = ReservationRequest.newInstance(capability, numContainers, minConcurrency, duration); list.add(rr); } ReservationRequests reqs = ReservationRequests.newInstance(list, resInt); ReservationDefinition rDef = ReservationDefinition.newInstance(resInfo.getArrival(), resInfo.getDeadline(), reqs, resInfo.getReservationName()); ReservationId reservationId = ReservationId.parseReservationId(resContext.getReservationId()); ReservationSubmissionRequest request = ReservationSubmissionRequest.newInstance(rDef, resContext.getQueue(), reservationId); return request; } /** * Function to update a Reservation to the RM. * * @param resContext provides information to construct the * ReservationUpdateRequest * @param hsr the servlet request * @return Response containing the status code * @throws AuthorizationException * @throws IOException * @throws InterruptedException */ @POST @Path("/reservation/update") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response updateReservation(ReservationUpdateRequestInfo resContext, @Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException { 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)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } final ReservationUpdateRequest reservation = createReservationUpdateRequest(resContext); ReservationUpdateResponseInfo resRespInfo; try { resRespInfo = callerUGI.doAs(new PrivilegedExceptionAction<ReservationUpdateResponseInfo>() { @Override public ReservationUpdateResponseInfo run() throws IOException, YarnException { rm.getClientRMService().updateReservation(reservation); return new ReservationUpdateResponseInfo(); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { throw new BadRequestException(ue.getCause().getMessage()); } LOG.info("Update reservation request failed", ue); throw ue; } return Response.status(Status.OK).entity(resRespInfo).build(); } private ReservationUpdateRequest createReservationUpdateRequest(ReservationUpdateRequestInfo resContext) throws IOException { // defending against a couple of common submission format problems if (resContext == null) { throw new BadRequestException("Input ReservationSubmissionContext should not be null"); } ReservationDefinitionInfo resInfo = resContext.getReservationDefinition(); if (resInfo == null) { throw new BadRequestException("Input ReservationDefinition should not be null"); } ReservationRequestsInfo resReqsInfo = resInfo.getReservationRequests(); if (resReqsInfo == null || resReqsInfo.getReservationRequest() == null || resReqsInfo.getReservationRequest().size() == 0) { throw new BadRequestException( "The ReservationDefinition should" + " contain at least one ReservationRequest"); } if (resContext.getReservationId() == null) { throw new BadRequestException("Update operations must specify an existing ReservaitonId"); } ReservationRequestInterpreter[] values = ReservationRequestInterpreter.values(); ReservationRequestInterpreter resInt = values[resReqsInfo.getReservationRequestsInterpreter()]; List<ReservationRequest> list = new ArrayList<ReservationRequest>(); for (ReservationRequestInfo resReqInfo : resReqsInfo.getReservationRequest()) { ResourceInfo rInfo = resReqInfo.getCapability(); Resource capability = Resource.newInstance(rInfo.getMemorySize(), rInfo.getvCores()); int numContainers = resReqInfo.getNumContainers(); int minConcurrency = resReqInfo.getMinConcurrency(); long duration = resReqInfo.getDuration(); ReservationRequest rr = ReservationRequest.newInstance(capability, numContainers, minConcurrency, duration); list.add(rr); } ReservationRequests reqs = ReservationRequests.newInstance(list, resInt); ReservationDefinition rDef = ReservationDefinition.newInstance(resInfo.getArrival(), resInfo.getDeadline(), reqs, resInfo.getReservationName()); ReservationUpdateRequest request = ReservationUpdateRequest.newInstance(rDef, ReservationId.parseReservationId(resContext.getReservationId())); return request; } /** * Function to delete a Reservation to the RM. * * @param resContext provides information to construct * the ReservationDeleteRequest * @param hsr the servlet request * @return Response containing the status code * @throws AuthorizationException when the user group information cannot be * retrieved. * @throws IOException when a {@link ReservationDeleteRequest} cannot be * created from the {@link ReservationDeleteRequestInfo}. This * exception is also thrown on * {@code ClientRMService.deleteReservation} invokation failure. * @throws InterruptedException if doAs action throws an InterruptedException. */ @POST @Path("/reservation/delete") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response deleteReservation(ReservationDeleteRequestInfo resContext, @Context HttpServletRequest hsr) throws AuthorizationException, IOException, InterruptedException { 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)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } final ReservationDeleteRequest reservation = createReservationDeleteRequest(resContext); ReservationDeleteResponseInfo resRespInfo; try { resRespInfo = callerUGI.doAs(new PrivilegedExceptionAction<ReservationDeleteResponseInfo>() { @Override public ReservationDeleteResponseInfo run() throws IOException, YarnException { rm.getClientRMService().deleteReservation(reservation); return new ReservationDeleteResponseInfo(); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { throw new BadRequestException(ue.getCause().getMessage()); } LOG.info("Update reservation request failed", ue); throw ue; } return Response.status(Status.OK).entity(resRespInfo).build(); } private ReservationDeleteRequest createReservationDeleteRequest(ReservationDeleteRequestInfo resContext) throws IOException { ReservationDeleteRequest request = ReservationDeleteRequest .newInstance(ReservationId.parseReservationId(resContext.getReservationId())); return request; } /** * Function to retrieve a list of all the reservations. */ @GET @Path("/reservation/list") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response listReservation(@QueryParam("queue") @DefaultValue("default") String queue, @QueryParam("reservation-id") @DefaultValue("") String reservationId, @QueryParam("start-time") @DefaultValue("0") long startTime, @QueryParam("end-time") @DefaultValue("-1") long endTime, @QueryParam("include-resource-allocations") @DefaultValue("false") boolean includeResourceAllocations, @Context HttpServletRequest hsr) throws Exception { init(); final ReservationListRequest request = ReservationListRequest.newInstance(queue, reservationId, startTime, endTime, includeResourceAllocations); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { throw new AuthorizationException("Unable to obtain user name, " + "user not authenticated"); } if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { String msg = "The default static user cannot carry out this operation."; return Response.status(Status.FORBIDDEN).entity(msg).build(); } ReservationListResponse resRespInfo; try { resRespInfo = callerUGI.doAs(new PrivilegedExceptionAction<ReservationListResponse>() { @Override public ReservationListResponse run() throws IOException, YarnException { return rm.getClientRMService().listReservations(request); } }); } catch (UndeclaredThrowableException ue) { if (ue.getCause() instanceof YarnException) { throw new BadRequestException(ue.getCause().getMessage()); } LOG.info("List reservation request failed", ue); throw ue; } ReservationListInfo resResponse = new ReservationListInfo(resRespInfo, includeResourceAllocations); return Response.status(Status.OK).entity(resResponse).build(); } }