YARN-8091. Revisit checkUserAccessToQueue RM REST API. (wangda)
[hadoop.git] / hadoop-yarn-project / hadoop-yarn / hadoop-yarn-server / hadoop-yarn-server-resourcemanager / src / main / java / org / apache / hadoop / yarn / server / resourcemanager / webapp / RMWebServices.java
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package org.apache.hadoop.yarn.server.resourcemanager.webapp;
20
21 import java.io.IOException;
22 import java.lang.reflect.UndeclaredThrowableException;
23 import java.security.AccessControlException;
24 import java.security.Principal;
25 import java.security.PrivilegedExceptionAction;
26 import java.text.ParseException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.EnumSet;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.Set;
38 import java.util.concurrent.ConcurrentMap;
39
40 import javax.servlet.http.HttpServletRequest;
41 import javax.servlet.http.HttpServletResponse;
42 import javax.ws.rs.Consumes;
43 import javax.ws.rs.DELETE;
44 import javax.ws.rs.DefaultValue;
45 import javax.ws.rs.FormParam;
46 import javax.ws.rs.GET;
47 import javax.ws.rs.POST;
48 import javax.ws.rs.PUT;
49 import javax.ws.rs.Path;
50 import javax.ws.rs.PathParam;
51 import javax.ws.rs.Produces;
52 import javax.ws.rs.QueryParam;
53 import javax.ws.rs.core.Context;
54 import javax.ws.rs.core.HttpHeaders;
55 import javax.ws.rs.core.MediaType;
56 import javax.ws.rs.core.Response;
57 import javax.ws.rs.core.Response.Status;
58
59 import org.apache.commons.logging.Log;
60 import org.apache.commons.logging.LogFactory;
61 import org.apache.hadoop.conf.Configuration;
62 import org.apache.hadoop.fs.CommonConfigurationKeys;
63 import org.apache.hadoop.http.JettyUtils;
64 import org.apache.hadoop.io.Text;
65 import org.apache.hadoop.security.UserGroupInformation;
66 import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
67 import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
68 import org.apache.hadoop.security.authorize.AuthorizationException;
69 import org.apache.hadoop.security.token.SecretManager.InvalidToken;
70 import org.apache.hadoop.security.token.Token;
71 import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationHandler;
72 import org.apache.hadoop.util.StringUtils;
73 import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenRequest;
74 import org.apache.hadoop.yarn.api.protocolrecords.CancelDelegationTokenResponse;
75 import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportRequest;
76 import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptsRequest;
77 import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportRequest;
78 import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest;
79 import org.apache.hadoop.yarn.api.protocolrecords.GetContainerReportRequest;
80 import org.apache.hadoop.yarn.api.protocolrecords.GetContainersRequest;
81 import org.apache.hadoop.yarn.api.protocolrecords.GetDelegationTokenRequest;
82 import org.apache.hadoop.yarn.api.protocolrecords.GetDelegationTokenResponse;
83 import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationRequest;
84 import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationResponse;
85 import org.apache.hadoop.yarn.api.protocolrecords.GetNewReservationRequest;
86 import org.apache.hadoop.yarn.api.protocolrecords.GetNewReservationResponse;
87 import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationRequest;
88 import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationResponse;
89 import org.apache.hadoop.yarn.api.protocolrecords.MoveApplicationAcrossQueuesRequest;
90 import org.apache.hadoop.yarn.api.protocolrecords.RenewDelegationTokenRequest;
91 import org.apache.hadoop.yarn.api.protocolrecords.RenewDelegationTokenResponse;
92 import org.apache.hadoop.yarn.api.protocolrecords.ReservationDeleteRequest;
93 import org.apache.hadoop.yarn.api.protocolrecords.ReservationListRequest;
94 import org.apache.hadoop.yarn.api.protocolrecords.ReservationListResponse;
95 import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionRequest;
96 import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionResponse;
97 import org.apache.hadoop.yarn.api.protocolrecords.ReservationUpdateRequest;
98 import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest;
99 import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationResponse;
100 import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationPriorityRequest;
101 import org.apache.hadoop.yarn.api.protocolrecords.UpdateApplicationTimeoutsRequest;
102 import org.apache.hadoop.yarn.api.records.ApplicationAccessType;
103 import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport;
104 import org.apache.hadoop.yarn.api.records.ApplicationId;
105 import org.apache.hadoop.yarn.api.records.ApplicationReport;
106 import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
107 import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType;
108 import org.apache.hadoop.yarn.api.records.ContainerReport;
109 import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
110 import org.apache.hadoop.yarn.api.records.NodeId;
111 import org.apache.hadoop.yarn.api.records.NodeLabel;
112 import org.apache.hadoop.yarn.api.records.NodeState;
113 import org.apache.hadoop.yarn.api.records.Priority;
114 import org.apache.hadoop.yarn.api.records.QueueACL;
115 import org.apache.hadoop.yarn.api.records.ReservationDefinition;
116 import org.apache.hadoop.yarn.api.records.ReservationId;
117 import org.apache.hadoop.yarn.api.records.ReservationRequest;
118 import org.apache.hadoop.yarn.api.records.ReservationRequestInterpreter;
119 import org.apache.hadoop.yarn.api.records.ReservationRequests;
120 import org.apache.hadoop.yarn.api.records.Resource;
121 import org.apache.hadoop.yarn.api.records.YarnApplicationState;
122 import org.apache.hadoop.yarn.conf.YarnConfiguration;
123 import org.apache.hadoop.yarn.exceptions.YarnException;
124 import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
125 import org.apache.hadoop.yarn.factories.RecordFactory;
126 import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider;
127 import org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier;
128 import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger;
129 import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger.AuditConstants;
130 import org.apache.hadoop.yarn.server.resourcemanager.RMServerUtils;
131 import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
132 import org.apache.hadoop.yarn.server.resourcemanager.nodelabels.NodeLabelsUtils;
133 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
134 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
135 import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode;
136 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.AbstractYarnScheduler;
137 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.MutableConfScheduler;
138 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.MutableConfigurationProvider;
139 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.activities.ActivitiesManager;
140 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
141 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
142 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue;
143 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
144 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.common.fica.FiCaSchedulerNode;
145 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
146 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
147 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ActivitiesInfo;
148 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppActivitiesInfo;
149 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptInfo;
150 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptsInfo;
151 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo;
152 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppPriority;
153 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppQueue;
154 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppState;
155 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppTimeoutInfo;
156 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppTimeoutsInfo;
157 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationStatisticsInfo;
158 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationSubmissionContextInfo;
159 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
160 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo;
161 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterInfo;
162 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
163 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.DelegationToken;
164 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.FairSchedulerInfo;
165 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.FifoSchedulerInfo;
166 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LabelsToNodesInfo;
167 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NewApplication;
168 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NewReservation;
169 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeInfo;
170 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelInfo;
171 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
172 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntry;
173 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
174 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
175 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
176 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
177 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDefinitionInfo;
178 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
179 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteResponseInfo;
180 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationListInfo;
181 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationRequestInfo;
182 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationRequestsInfo;
183 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
184 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
185 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateResponseInfo;
186 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo;
187 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerInfo;
188 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo;
189 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.StatisticsItemInfo;
190 import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
191 import org.apache.hadoop.yarn.server.utils.BuilderUtils;
192 import org.apache.hadoop.yarn.server.webapp.WebServices;
193 import org.apache.hadoop.yarn.server.webapp.dao.ContainerInfo;
194 import org.apache.hadoop.yarn.server.webapp.dao.ContainersInfo;
195 import org.apache.hadoop.yarn.util.AdHocLogDumper;
196 import org.apache.hadoop.yarn.util.ConverterUtils;
197 import org.apache.hadoop.yarn.util.Times;
198 import org.apache.hadoop.yarn.webapp.BadRequestException;
199 import org.apache.hadoop.yarn.webapp.ForbiddenException;
200 import org.apache.hadoop.yarn.webapp.NotFoundException;
201 import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
202 import org.apache.hadoop.yarn.webapp.dao.SchedConfUpdateInfo;
203
204 import com.google.common.annotations.VisibleForTesting;
205 import com.google.inject.Inject;
206 import com.google.inject.Singleton;
207
208 @Singleton
209 @Path(RMWSConsts.RM_WEB_SERVICE_PATH)
210 public class RMWebServices extends WebServices implements RMWebServiceProtocol {
211
212 private static final Log LOG =
213 LogFactory.getLog(RMWebServices.class.getName());
214
215 private final ResourceManager rm;
216 private static RecordFactory recordFactory =
217 RecordFactoryProvider.getRecordFactory(null);
218 private final Configuration conf;
219 private @Context HttpServletResponse response;
220
221 // -------Default values of QueryParams for RMWebServiceProtocol--------
222
223 public static final String DEFAULT_QUEUE = "default";
224 public static final String DEFAULT_RESERVATION_ID = "";
225 public static final String DEFAULT_START_TIME = "0";
226 public static final String DEFAULT_END_TIME = "-1";
227 public static final String DEFAULT_INCLUDE_RESOURCE = "false";
228
229 @VisibleForTesting
230 boolean isCentralizedNodeLabelConfiguration = true;
231
232 public final static String DELEGATION_TOKEN_HEADER =
233 "Hadoop-YARN-RM-Delegation-Token";
234
235 @Inject
236 public RMWebServices(final ResourceManager rm, Configuration conf) {
237 // don't inject, always take appBaseRoot from RM.
238 super(null);
239 this.rm = rm;
240 this.conf = conf;
241 isCentralizedNodeLabelConfiguration =
242 YarnConfiguration.isCentralizedNodeLabelConfiguration(conf);
243 }
244
245 RMWebServices(ResourceManager rm, Configuration conf,
246 HttpServletResponse response) {
247 this(rm, conf);
248 this.response = response;
249 }
250
251 protected Boolean hasAccess(RMApp app, HttpServletRequest hsr) {
252 // Check for the authorization.
253 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
254 List<String> forwardedAddresses = null;
255 String forwardedFor = hsr.getHeader(RMWSConsts.FORWARDED_FOR);
256 if (forwardedFor != null) {
257 forwardedAddresses = Arrays.asList(forwardedFor.split(","));
258 }
259 if (callerUGI != null
260 && !(this.rm.getApplicationACLsManager().checkAccess(callerUGI,
261 ApplicationAccessType.VIEW_APP, app.getUser(),
262 app.getApplicationId())
263 || this.rm.getQueueACLsManager().checkAccess(callerUGI,
264 QueueACL.ADMINISTER_QUEUE, app, hsr.getRemoteAddr(),
265 forwardedAddresses))) {
266 return false;
267 }
268 return true;
269 }
270
271 private void init() {
272 // clear content type
273 response.setContentType(null);
274 }
275
276 @GET
277 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
278 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
279 @Override
280 public ClusterInfo get() {
281 return getClusterInfo();
282 }
283
284 @GET
285 @Path(RMWSConsts.INFO)
286 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
287 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
288 @Override
289 public ClusterInfo getClusterInfo() {
290 init();
291 return new ClusterInfo(this.rm);
292 }
293
294 @GET
295 @Path(RMWSConsts.METRICS)
296 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
297 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
298 @Override
299 public ClusterMetricsInfo getClusterMetricsInfo() {
300 init();
301 return new ClusterMetricsInfo(this.rm);
302 }
303
304 @GET
305 @Path(RMWSConsts.SCHEDULER)
306 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
307 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
308 @Override
309 public SchedulerTypeInfo getSchedulerInfo() {
310 init();
311 ResourceScheduler rs = rm.getResourceScheduler();
312 SchedulerInfo sinfo;
313 if (rs instanceof CapacityScheduler) {
314 CapacityScheduler cs = (CapacityScheduler) rs;
315 CSQueue root = cs.getRootQueue();
316 sinfo = new CapacitySchedulerInfo(root, cs);
317 } else if (rs instanceof FairScheduler) {
318 FairScheduler fs = (FairScheduler) rs;
319 sinfo = new FairSchedulerInfo(fs);
320 } else if (rs instanceof FifoScheduler) {
321 sinfo = new FifoSchedulerInfo(this.rm);
322 } else {
323 throw new NotFoundException("Unknown scheduler configured");
324 }
325 return new SchedulerTypeInfo(sinfo);
326 }
327
328 @POST
329 @Path(RMWSConsts.SCHEDULER_LOGS)
330 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
331 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
332 @Override
333 public String dumpSchedulerLogs(@FormParam(RMWSConsts.TIME) String time,
334 @Context HttpServletRequest hsr) throws IOException {
335 init();
336 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
337 ApplicationACLsManager aclsManager = rm.getApplicationACLsManager();
338 if (aclsManager.areACLsEnabled()) {
339 if (callerUGI == null || !aclsManager.isAdmin(callerUGI)) {
340 String msg = "Only admins can carry out this operation.";
341 throw new ForbiddenException(msg);
342 }
343 }
344 ResourceScheduler rs = rm.getResourceScheduler();
345 int period = Integer.parseInt(time);
346 if (period <= 0) {
347 throw new BadRequestException("Period must be greater than 0");
348 }
349 final String logHierarchy =
350 "org.apache.hadoop.yarn.server.resourcemanager.scheduler";
351 String logfile = "yarn-scheduler-debug.log";
352 if (rs instanceof CapacityScheduler) {
353 logfile = "yarn-capacity-scheduler-debug.log";
354 } else if (rs instanceof FairScheduler) {
355 logfile = "yarn-fair-scheduler-debug.log";
356 }
357 AdHocLogDumper dumper = new AdHocLogDumper(logHierarchy, logfile);
358 // time period is sent to us in seconds
359 dumper.dumpLogs("DEBUG", period * 1000);
360 return "Capacity scheduler logs are being created.";
361 }
362
363 @GET
364 @Path(RMWSConsts.NODES)
365 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
366 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
367 @Override
368 public NodesInfo getNodes(@QueryParam(RMWSConsts.STATES) String states) {
369 init();
370 ResourceScheduler sched = this.rm.getResourceScheduler();
371 if (sched == null) {
372 throw new NotFoundException("Null ResourceScheduler instance");
373 }
374
375 EnumSet<NodeState> acceptedStates;
376 if (states == null) {
377 acceptedStates = EnumSet.allOf(NodeState.class);
378 } else {
379 acceptedStates = EnumSet.noneOf(NodeState.class);
380 for (String stateStr : states.split(",")) {
381 acceptedStates
382 .add(NodeState.valueOf(StringUtils.toUpperCase(stateStr)));
383 }
384 }
385
386 Collection<RMNode> rmNodes =
387 RMServerUtils.queryRMNodes(this.rm.getRMContext(), acceptedStates);
388 NodesInfo nodesInfo = new NodesInfo();
389 for (RMNode rmNode : rmNodes) {
390 NodeInfo nodeInfo = new NodeInfo(rmNode, sched);
391 if (EnumSet
392 .of(NodeState.LOST, NodeState.DECOMMISSIONED, NodeState.REBOOTED)
393 .contains(rmNode.getState())) {
394 nodeInfo.setNodeHTTPAddress(RMWSConsts.EMPTY);
395 }
396 nodesInfo.add(nodeInfo);
397 }
398
399 return nodesInfo;
400 }
401
402 @GET
403 @Path(RMWSConsts.NODES_NODEID)
404 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
405 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
406 @Override
407 public NodeInfo getNode(@PathParam(RMWSConsts.NODEID) String nodeId) {
408 init();
409 if (nodeId == null || nodeId.isEmpty()) {
410 throw new NotFoundException("nodeId, " + nodeId + ", is empty or null");
411 }
412 ResourceScheduler sched = this.rm.getResourceScheduler();
413 if (sched == null) {
414 throw new NotFoundException("Null ResourceScheduler instance");
415 }
416 NodeId nid = NodeId.fromString(nodeId);
417 RMNode ni = this.rm.getRMContext().getRMNodes().get(nid);
418 boolean isInactive = false;
419 if (ni == null) {
420 ni = this.rm.getRMContext().getInactiveRMNodes().get(nid);
421 if (ni == null) {
422 throw new NotFoundException("nodeId, " + nodeId + ", is not found");
423 }
424 isInactive = true;
425 }
426 NodeInfo nodeInfo = new NodeInfo(ni, sched);
427 if (isInactive) {
428 nodeInfo.setNodeHTTPAddress(RMWSConsts.EMPTY);
429 }
430 return nodeInfo;
431 }
432
433 @GET
434 @Path(RMWSConsts.APPS)
435 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
436 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
437 @Override
438 public AppsInfo getApps(@Context HttpServletRequest hsr,
439 @QueryParam(RMWSConsts.STATE) String stateQuery,
440 @QueryParam(RMWSConsts.STATES) Set<String> statesQuery,
441 @QueryParam(RMWSConsts.FINAL_STATUS) String finalStatusQuery,
442 @QueryParam(RMWSConsts.USER) String userQuery,
443 @QueryParam(RMWSConsts.QUEUE) String queueQuery,
444 @QueryParam(RMWSConsts.LIMIT) String count,
445 @QueryParam(RMWSConsts.STARTED_TIME_BEGIN) String startedBegin,
446 @QueryParam(RMWSConsts.STARTED_TIME_END) String startedEnd,
447 @QueryParam(RMWSConsts.FINISHED_TIME_BEGIN) String finishBegin,
448 @QueryParam(RMWSConsts.FINISHED_TIME_END) String finishEnd,
449 @QueryParam(RMWSConsts.APPLICATION_TYPES) Set<String> applicationTypes,
450 @QueryParam(RMWSConsts.APPLICATION_TAGS) Set<String> applicationTags,
451 @QueryParam(RMWSConsts.DESELECTS) Set<String> unselectedFields) {
452 boolean checkCount = false;
453 boolean checkStart = false;
454 boolean checkEnd = false;
455 boolean checkAppTypes = false;
456 boolean checkAppStates = false;
457 boolean checkAppTags = false;
458 long countNum = 0;
459
460 // set values suitable in case both of begin/end not specified
461 long sBegin = 0;
462 long sEnd = Long.MAX_VALUE;
463 long fBegin = 0;
464 long fEnd = Long.MAX_VALUE;
465
466 init();
467 if (count != null && !count.isEmpty()) {
468 checkCount = true;
469 countNum = Long.parseLong(count);
470 if (countNum <= 0) {
471 throw new BadRequestException("limit value must be greater then 0");
472 }
473 }
474
475 if (startedBegin != null && !startedBegin.isEmpty()) {
476 checkStart = true;
477 sBegin = Long.parseLong(startedBegin);
478 if (sBegin < 0) {
479 throw new BadRequestException(
480 "startedTimeBegin must be greater than 0");
481 }
482 }
483 if (startedEnd != null && !startedEnd.isEmpty()) {
484 checkStart = true;
485 sEnd = Long.parseLong(startedEnd);
486 if (sEnd < 0) {
487 throw new BadRequestException("startedTimeEnd must be greater than 0");
488 }
489 }
490 if (sBegin > sEnd) {
491 throw new BadRequestException(
492 "startedTimeEnd must be greater than startTimeBegin");
493 }
494
495 if (finishBegin != null && !finishBegin.isEmpty()) {
496 checkEnd = true;
497 fBegin = Long.parseLong(finishBegin);
498 if (fBegin < 0) {
499 throw new BadRequestException("finishTimeBegin must be greater than 0");
500 }
501 }
502 if (finishEnd != null && !finishEnd.isEmpty()) {
503 checkEnd = true;
504 fEnd = Long.parseLong(finishEnd);
505 if (fEnd < 0) {
506 throw new BadRequestException("finishTimeEnd must be greater than 0");
507 }
508 }
509 if (fBegin > fEnd) {
510 throw new BadRequestException(
511 "finishTimeEnd must be greater than finishTimeBegin");
512 }
513
514 Set<String> appTypes = parseQueries(applicationTypes, false);
515 if (!appTypes.isEmpty()) {
516 checkAppTypes = true;
517 }
518
519 Set<String> appTags = parseQueries(applicationTags, false);
520 if (!appTags.isEmpty()) {
521 checkAppTags = true;
522 }
523
524 // stateQuery is deprecated.
525 if (stateQuery != null && !stateQuery.isEmpty()) {
526 statesQuery.add(stateQuery);
527 }
528 Set<String> appStates = parseQueries(statesQuery, true);
529 if (!appStates.isEmpty()) {
530 checkAppStates = true;
531 }
532
533 GetApplicationsRequest request = GetApplicationsRequest.newInstance();
534
535 if (checkStart) {
536 request.setStartRange(sBegin, sEnd);
537 }
538
539 if (checkEnd) {
540 request.setFinishRange(fBegin, fEnd);
541 }
542
543 if (checkCount) {
544 request.setLimit(countNum);
545 }
546
547 if (checkAppTypes) {
548 request.setApplicationTypes(appTypes);
549 }
550
551 if (checkAppTags) {
552 request.setApplicationTags(appTags);
553 }
554
555 if (checkAppStates) {
556 request.setApplicationStates(appStates);
557 }
558
559 if (queueQuery != null && !queueQuery.isEmpty()) {
560 ResourceScheduler rs = rm.getResourceScheduler();
561 if (rs instanceof CapacityScheduler) {
562 CapacityScheduler cs = (CapacityScheduler) rs;
563 // validate queue exists
564 try {
565 cs.getQueueInfo(queueQuery, false, false);
566 } catch (IOException e) {
567 throw new BadRequestException(e.getMessage());
568 }
569 }
570 Set<String> queues = new HashSet<String>(1);
571 queues.add(queueQuery);
572 request.setQueues(queues);
573 }
574
575 if (userQuery != null && !userQuery.isEmpty()) {
576 Set<String> users = new HashSet<String>(1);
577 users.add(userQuery);
578 request.setUsers(users);
579 }
580
581 List<ApplicationReport> appReports = null;
582 try {
583 appReports = rm.getClientRMService().getApplications(request)
584 .getApplicationList();
585 } catch (YarnException e) {
586 LOG.error("Unable to retrieve apps from ClientRMService", e);
587 throw new YarnRuntimeException(
588 "Unable to retrieve apps from ClientRMService", e);
589 }
590
591 final ConcurrentMap<ApplicationId, RMApp> apps =
592 rm.getRMContext().getRMApps();
593 AppsInfo allApps = new AppsInfo();
594 for (ApplicationReport report : appReports) {
595 RMApp rmapp = apps.get(report.getApplicationId());
596 if (rmapp == null) {
597 continue;
598 }
599
600 if (finalStatusQuery != null && !finalStatusQuery.isEmpty()) {
601 FinalApplicationStatus.valueOf(finalStatusQuery);
602 if (!rmapp.getFinalApplicationStatus().toString()
603 .equalsIgnoreCase(finalStatusQuery)) {
604 continue;
605 }
606 }
607
608 DeSelectFields deSelectFields = new DeSelectFields();
609 deSelectFields.initFields(unselectedFields);
610
611 AppInfo app = new AppInfo(rm, rmapp, hasAccess(rmapp, hsr),
612 WebAppUtils.getHttpSchemePrefix(conf), deSelectFields);
613 allApps.add(app);
614 }
615 return allApps;
616 }
617
618 @GET
619 @Path(RMWSConsts.SCHEDULER_ACTIVITIES)
620 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
621 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
622 @Override
623 public ActivitiesInfo getActivities(@Context HttpServletRequest hsr,
624 @QueryParam(RMWSConsts.NODEID) String nodeId) {
625 YarnScheduler scheduler = rm.getRMContext().getScheduler();
626
627 if (scheduler instanceof AbstractYarnScheduler) {
628 String errMessage = "";
629
630 AbstractYarnScheduler abstractYarnScheduler =
631 (AbstractYarnScheduler) scheduler;
632
633 ActivitiesManager activitiesManager =
634 abstractYarnScheduler.getActivitiesManager();
635 if (null == activitiesManager) {
636 errMessage = "Not Capacity Scheduler";
637 return new ActivitiesInfo(errMessage, nodeId);
638 }
639
640 List<FiCaSchedulerNode> nodeList =
641 abstractYarnScheduler.getNodeTracker().getAllNodes();
642
643 boolean illegalInput = false;
644
645 if (nodeList.size() == 0) {
646 illegalInput = true;
647 errMessage = "No node manager running in the cluster";
648 } else {
649 if (nodeId != null) {
650 String hostName = nodeId;
651 String portName = "";
652 if (nodeId.contains(":")) {
653 int index = nodeId.indexOf(":");
654 hostName = nodeId.substring(0, index);
655 portName = nodeId.substring(index + 1);
656 }
657
658 boolean correctNodeId = false;
659 for (FiCaSchedulerNode node : nodeList) {
660 if ((portName.equals("")
661 && node.getRMNode().getHostName().equals(hostName))
662 || (!portName.equals("")
663 && node.getRMNode().getHostName().equals(hostName)
664 && String.valueOf(node.getRMNode().getCommandPort())
665 .equals(portName))) {
666 correctNodeId = true;
667 nodeId = node.getNodeID().toString();
668 break;
669 }
670 }
671 if (!correctNodeId) {
672 illegalInput = true;
673 errMessage = "Cannot find node manager with given node id";
674 }
675 }
676 }
677
678 if (!illegalInput) {
679 activitiesManager.recordNextNodeUpdateActivities(nodeId);
680 return activitiesManager.getActivitiesInfo(nodeId);
681 }
682
683 // Return a activities info with error message
684 return new ActivitiesInfo(errMessage, nodeId);
685 }
686
687 return null;
688 }
689
690 @GET
691 @Path(RMWSConsts.SCHEDULER_APP_ACTIVITIES)
692 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
693 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
694 @Override
695 public AppActivitiesInfo getAppActivities(@Context HttpServletRequest hsr,
696 @QueryParam(RMWSConsts.APP_ID) String appId,
697 @QueryParam(RMWSConsts.MAX_TIME) String time) {
698 YarnScheduler scheduler = rm.getRMContext().getScheduler();
699
700 if (scheduler instanceof AbstractYarnScheduler) {
701 AbstractYarnScheduler abstractYarnScheduler =
702 (AbstractYarnScheduler) scheduler;
703
704 ActivitiesManager activitiesManager =
705 abstractYarnScheduler.getActivitiesManager();
706 if (null == activitiesManager) {
707 String errMessage = "Not Capacity Scheduler";
708 return new AppActivitiesInfo(errMessage, appId);
709 }
710
711 if (appId == null) {
712 String errMessage = "Must provide an application Id";
713 return new AppActivitiesInfo(errMessage, null);
714 }
715
716 double maxTime = 3.0;
717
718 if (time != null) {
719 if (time.contains(".")) {
720 maxTime = Double.parseDouble(time);
721 } else {
722 maxTime = Double.parseDouble(time + ".0");
723 }
724 }
725
726 ApplicationId applicationId;
727 try {
728 applicationId = ApplicationId.fromString(appId);
729 activitiesManager.turnOnAppActivitiesRecording(applicationId, maxTime);
730 AppActivitiesInfo appActivitiesInfo =
731 activitiesManager.getAppActivitiesInfo(applicationId);
732
733 return appActivitiesInfo;
734 } catch (Exception e) {
735 String errMessage = "Cannot find application with given appId";
736 return new AppActivitiesInfo(errMessage, appId);
737 }
738
739 }
740 return null;
741 }
742
743 @GET
744 @Path(RMWSConsts.APP_STATISTICS)
745 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
746 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
747 @Override
748 public ApplicationStatisticsInfo getAppStatistics(
749 @Context HttpServletRequest hsr,
750 @QueryParam(RMWSConsts.STATES) Set<String> stateQueries,
751 @QueryParam(RMWSConsts.APPLICATION_TYPES) Set<String> typeQueries) {
752 init();
753
754 // parse the params and build the scoreboard
755 // converting state/type name to lowercase
756 Set<String> states = parseQueries(stateQueries, true);
757 Set<String> types = parseQueries(typeQueries, false);
758 // if no types, counts the applications of any types
759 if (types.size() == 0) {
760 types.add(RMWSConsts.ANY);
761 } else if (types.size() != 1) {
762 throw new BadRequestException("# of applicationTypes = " + types.size()
763 + ", we temporarily support at most one applicationType");
764 }
765 // if no states, returns the counts of all RMAppStates
766 if (states.size() == 0) {
767 for (YarnApplicationState state : YarnApplicationState.values()) {
768 states.add(StringUtils.toLowerCase(state.toString()));
769 }
770 }
771 // in case we extend to multiple applicationTypes in the future
772 Map<YarnApplicationState, Map<String, Long>> scoreboard =
773 buildScoreboard(states, types);
774
775 // go through the apps in RM to count the numbers, ignoring the case of
776 // the state/type name
777 ConcurrentMap<ApplicationId, RMApp> apps = rm.getRMContext().getRMApps();
778 for (RMApp rmapp : apps.values()) {
779 YarnApplicationState state = rmapp.createApplicationState();
780 String type = StringUtils.toLowerCase(rmapp.getApplicationType().trim());
781 if (states.contains(StringUtils.toLowerCase(state.toString()))) {
782 if (types.contains(RMWSConsts.ANY)) {
783 countApp(scoreboard, state, RMWSConsts.ANY);
784 } else if (types.contains(type)) {
785 countApp(scoreboard, state, type);
786 }
787 }
788 }
789
790 // fill the response object
791 ApplicationStatisticsInfo appStatInfo = new ApplicationStatisticsInfo();
792 for (Map.Entry<YarnApplicationState, Map<String, Long>> partScoreboard : scoreboard
793 .entrySet()) {
794 for (Map.Entry<String, Long> statEntry : partScoreboard.getValue()
795 .entrySet()) {
796 StatisticsItemInfo statItem = new StatisticsItemInfo(
797 partScoreboard.getKey(), statEntry.getKey(), statEntry.getValue());
798 appStatInfo.add(statItem);
799 }
800 }
801 return appStatInfo;
802 }
803
804 private static Map<YarnApplicationState, Map<String, Long>> buildScoreboard(
805 Set<String> states, Set<String> types) {
806 Map<YarnApplicationState, Map<String, Long>> scoreboard =
807 new HashMap<YarnApplicationState, Map<String, Long>>();
808 // default states will result in enumerating all YarnApplicationStates
809 assert !states.isEmpty();
810 for (String state : states) {
811 Map<String, Long> partScoreboard = new HashMap<String, Long>();
812 scoreboard.put(
813 YarnApplicationState.valueOf(StringUtils.toUpperCase(state)),
814 partScoreboard);
815 // types is verified no to be empty
816 for (String type : types) {
817 partScoreboard.put(type, 0L);
818 }
819 }
820 return scoreboard;
821 }
822
823 private static void countApp(
824 Map<YarnApplicationState, Map<String, Long>> scoreboard,
825 YarnApplicationState state, String type) {
826 Map<String, Long> partScoreboard = scoreboard.get(state);
827 Long count = partScoreboard.get(type);
828 partScoreboard.put(type, count + 1L);
829 }
830
831 @GET
832 @Path(RMWSConsts.APPS_APPID)
833 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
834 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
835 @Override
836 public AppInfo getApp(@Context HttpServletRequest hsr,
837 @PathParam(RMWSConsts.APPID) String appId,
838 @QueryParam(RMWSConsts.DESELECTS) Set<String> unselectedFields) {
839 init();
840 ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId);
841 RMApp app = rm.getRMContext().getRMApps().get(id);
842 if (app == null) {
843 throw new NotFoundException("app with id: " + appId + " not found");
844 }
845
846 DeSelectFields deSelectFields = new DeSelectFields();
847 deSelectFields.initFields(unselectedFields);
848
849 return new AppInfo(rm, app, hasAccess(app, hsr), hsr.getScheme() + "://",
850 deSelectFields);
851 }
852
853 @GET
854 @Path(RMWSConsts.APPS_APPID_APPATTEMPTS)
855 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
856 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
857 @Override
858 public AppAttemptsInfo getAppAttempts(@Context HttpServletRequest hsr,
859 @PathParam(RMWSConsts.APPID) String appId) {
860
861 init();
862 ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId);
863 RMApp app = rm.getRMContext().getRMApps().get(id);
864 if (app == null) {
865 throw new NotFoundException("app with id: " + appId + " not found");
866 }
867
868 AppAttemptsInfo appAttemptsInfo = new AppAttemptsInfo();
869 for (RMAppAttempt attempt : app.getAppAttempts().values()) {
870 AppAttemptInfo attemptInfo = new AppAttemptInfo(rm, attempt,
871 app.getUser(), hsr.getScheme() + "://");
872 appAttemptsInfo.add(attemptInfo);
873 }
874
875 return appAttemptsInfo;
876 }
877
878 @GET
879 @Path(RMWSConsts.APPS_APPID_APPATTEMPTS_APPATTEMPTID)
880 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
881 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
882 @Override
883 public org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo getAppAttempt(
884 @Context HttpServletRequest req, @Context HttpServletResponse res,
885 @PathParam(RMWSConsts.APPID) String appId,
886 @PathParam(RMWSConsts.APPATTEMPTID) String appAttemptId) {
887 init(res);
888 return super.getAppAttempt(req, res, appId, appAttemptId);
889 }
890
891 @GET
892 @Path(RMWSConsts.APPS_APPID_APPATTEMPTS_APPATTEMPTID_CONTAINERS)
893 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
894 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
895 @Override
896 public ContainersInfo getContainers(@Context HttpServletRequest req,
897 @Context HttpServletResponse res,
898 @PathParam(RMWSConsts.APPID) String appId,
899 @PathParam(RMWSConsts.APPATTEMPTID) String appAttemptId) {
900 init(res);
901 return super.getContainers(req, res, appId, appAttemptId);
902 }
903
904 @GET
905 @Path("/apps/{appid}/appattempts/{appattemptid}/containers/{containerid}")
906 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
907 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
908 @Override
909 public ContainerInfo getContainer(@Context HttpServletRequest req,
910 @Context HttpServletResponse res,
911 @PathParam(RMWSConsts.APPID) String appId,
912 @PathParam(RMWSConsts.APPATTEMPTID) String appAttemptId,
913 @PathParam("containerid") String containerId) {
914 init(res);
915 return super.getContainer(req, res, appId, appAttemptId, containerId);
916 }
917
918 @GET
919 @Path("/apps/{appid}/state")
920 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
921 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
922 @Override
923 public AppState getAppState(@Context HttpServletRequest hsr,
924 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException {
925 init();
926 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
927 String userName = "";
928 if (callerUGI != null) {
929 userName = callerUGI.getUserName();
930 }
931 RMApp app = null;
932 try {
933 app = getRMAppForAppId(appId);
934 } catch (NotFoundException e) {
935 RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_STATE,
936 "UNKNOWN", "RMWebService",
937 "Trying to get state of an absent application " + appId);
938 throw e;
939 }
940
941 AppState ret = new AppState();
942 ret.setState(app.getState().toString());
943
944 return ret;
945 }
946
947 // can't return POJO because we can't control the status code
948 // it's always set to 200 when we need to allow it to be set
949 // to 202
950
951 @PUT
952 @Path(RMWSConsts.APPS_APPID_STATE)
953 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
954 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
955 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
956 @Override
957 public Response updateAppState(AppState targetState,
958 @Context HttpServletRequest hsr,
959 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException,
960 YarnException, InterruptedException, IOException {
961
962 init();
963 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
964 if (callerUGI == null) {
965 String msg = "Unable to obtain user name, user not authenticated";
966 throw new AuthorizationException(msg);
967 }
968
969 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
970 String msg = "The default static user cannot carry out this operation.";
971 return Response.status(Status.FORBIDDEN).entity(msg).build();
972 }
973
974 String userName = callerUGI.getUserName();
975 RMApp app = null;
976 try {
977 app = getRMAppForAppId(appId);
978 } catch (NotFoundException e) {
979 RMAuditLogger.logFailure(userName, AuditConstants.KILL_APP_REQUEST,
980 "UNKNOWN", "RMWebService",
981 "Trying to kill an absent application " + appId);
982 throw e;
983 }
984
985 if (!app.getState().toString().equals(targetState.getState())) {
986 // user is attempting to change state. right we only
987 // allow users to kill the app
988
989 if (targetState.getState()
990 .equals(YarnApplicationState.KILLED.toString())) {
991 return killApp(app, callerUGI, hsr, targetState.getDiagnostics());
992 }
993 throw new BadRequestException(
994 "Only '" + YarnApplicationState.KILLED.toString()
995 + "' is allowed as a target state.");
996 }
997
998 AppState ret = new AppState();
999 ret.setState(app.getState().toString());
1000
1001 return Response.status(Status.OK).entity(ret).build();
1002 }
1003
1004 @GET
1005 @Path(RMWSConsts.GET_NODE_TO_LABELS)
1006 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1007 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1008 @Override
1009 public NodeToLabelsInfo getNodeToLabels(@Context HttpServletRequest hsr)
1010 throws IOException {
1011 init();
1012
1013 NodeToLabelsInfo ntl = new NodeToLabelsInfo();
1014 HashMap<String, NodeLabelsInfo> ntlMap = ntl.getNodeToLabels();
1015 Map<NodeId, Set<NodeLabel>> nodeIdToLabels =
1016 rm.getRMContext().getNodeLabelManager().getNodeLabelsInfo();
1017
1018 for (Map.Entry<NodeId, Set<NodeLabel>> nitle : nodeIdToLabels.entrySet()) {
1019 List<NodeLabel> labels = new ArrayList<NodeLabel>(nitle.getValue());
1020 ntlMap.put(nitle.getKey().toString(), new NodeLabelsInfo(labels));
1021 }
1022
1023 return ntl;
1024 }
1025
1026 @GET
1027 @Path(RMWSConsts.LABEL_MAPPINGS)
1028 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1029 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1030 @Override
1031 public LabelsToNodesInfo getLabelsToNodes(
1032 @QueryParam(RMWSConsts.LABELS) Set<String> labels) throws IOException {
1033 init();
1034
1035 LabelsToNodesInfo lts = new LabelsToNodesInfo();
1036 Map<NodeLabelInfo, NodeIDsInfo> ltsMap = lts.getLabelsToNodes();
1037 Map<NodeLabel, Set<NodeId>> labelsToNodeId = null;
1038 if (labels == null || labels.size() == 0) {
1039 labelsToNodeId =
1040 rm.getRMContext().getNodeLabelManager().getLabelsInfoToNodes();
1041 } else {
1042 labelsToNodeId =
1043 rm.getRMContext().getNodeLabelManager().getLabelsInfoToNodes(labels);
1044 }
1045
1046 for (Entry<NodeLabel, Set<NodeId>> entry : labelsToNodeId.entrySet()) {
1047 List<String> nodeIdStrList = new ArrayList<String>();
1048 for (NodeId nodeId : entry.getValue()) {
1049 nodeIdStrList.add(nodeId.toString());
1050 }
1051 ltsMap.put(new NodeLabelInfo(entry.getKey()),
1052 new NodeIDsInfo(nodeIdStrList));
1053 }
1054 return lts;
1055 }
1056
1057 @POST
1058 @Path(RMWSConsts.REPLACE_NODE_TO_LABELS)
1059 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1060 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1061 @Override
1062 public Response replaceLabelsOnNodes(
1063 final NodeToLabelsEntryList newNodeToLabels,
1064 @Context HttpServletRequest hsr) throws IOException {
1065 Map<NodeId, Set<String>> nodeIdToLabels =
1066 new HashMap<NodeId, Set<String>>();
1067
1068 for (NodeToLabelsEntry nitle : newNodeToLabels.getNodeToLabels()) {
1069 nodeIdToLabels.put(
1070 ConverterUtils.toNodeIdWithDefaultPort(nitle.getNodeId()),
1071 new HashSet<String>(nitle.getNodeLabels()));
1072 }
1073
1074 return replaceLabelsOnNode(nodeIdToLabels, hsr, "/replace-node-to-labels");
1075 }
1076
1077 @POST
1078 @Path(RMWSConsts.NODES_NODEID_REPLACE_LABELS)
1079 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1080 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1081 @Override
1082 public Response replaceLabelsOnNode(
1083 @QueryParam("labels") Set<String> newNodeLabelsName,
1084 @Context HttpServletRequest hsr, @PathParam("nodeId") String nodeId)
1085 throws Exception {
1086 NodeId nid = ConverterUtils.toNodeIdWithDefaultPort(nodeId);
1087 Map<NodeId, Set<String>> newLabelsForNode =
1088 new HashMap<NodeId, Set<String>>();
1089 newLabelsForNode.put(nid, new HashSet<String>(newNodeLabelsName));
1090
1091 return replaceLabelsOnNode(newLabelsForNode, hsr,
1092 "/nodes/nodeid/replace-labels");
1093 }
1094
1095 private Response replaceLabelsOnNode(
1096 Map<NodeId, Set<String>> newLabelsForNode, HttpServletRequest hsr,
1097 String operation) throws IOException {
1098 init();
1099
1100 NodeLabelsUtils.verifyCentralizedNodeLabelConfEnabled("replaceLabelsOnNode",
1101 isCentralizedNodeLabelConfiguration);
1102
1103 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1104 if (callerUGI == null) {
1105 String msg = "Unable to obtain user name, user not authenticated for"
1106 + " post to ..." + operation;
1107 throw new AuthorizationException(msg);
1108 }
1109
1110 if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) {
1111 String msg = "User " + callerUGI.getShortUserName() + " not authorized"
1112 + " for post to ..." + operation;
1113 throw new AuthorizationException(msg);
1114 }
1115 try {
1116 rm.getRMContext().getNodeLabelManager()
1117 .replaceLabelsOnNode(newLabelsForNode);
1118 } catch (IOException e) {
1119 throw new BadRequestException(e);
1120 }
1121
1122 return Response.status(Status.OK).build();
1123 }
1124
1125 @GET
1126 @Path(RMWSConsts.GET_NODE_LABELS)
1127 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1128 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1129 @Override
1130 public NodeLabelsInfo getClusterNodeLabels(@Context HttpServletRequest hsr)
1131 throws IOException {
1132 init();
1133
1134 List<NodeLabel> nodeLabels =
1135 rm.getRMContext().getNodeLabelManager().getClusterNodeLabels();
1136 NodeLabelsInfo ret = new NodeLabelsInfo(nodeLabels);
1137
1138 return ret;
1139 }
1140
1141 @POST
1142 @Path(RMWSConsts.ADD_NODE_LABELS)
1143 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1144 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1145 @Override
1146 public Response addToClusterNodeLabels(final NodeLabelsInfo newNodeLabels,
1147 @Context HttpServletRequest hsr) throws Exception {
1148 init();
1149
1150 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1151 if (callerUGI == null) {
1152 String msg = "Unable to obtain user name, user not authenticated for"
1153 + " post to .../add-node-labels";
1154 throw new AuthorizationException(msg);
1155 }
1156 if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) {
1157 String msg = "User " + callerUGI.getShortUserName() + " not authorized"
1158 + " for post to .../add-node-labels ";
1159 throw new AuthorizationException(msg);
1160 }
1161
1162 try {
1163 rm.getRMContext().getNodeLabelManager()
1164 .addToCluserNodeLabels(newNodeLabels.getNodeLabels());
1165 } catch (IOException e) {
1166 throw new BadRequestException(e);
1167 }
1168
1169 return Response.status(Status.OK).build();
1170
1171 }
1172
1173 @POST
1174 @Path(RMWSConsts.REMOVE_NODE_LABELS)
1175 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1176 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1177 @Override
1178 public Response removeFromCluserNodeLabels(
1179 @QueryParam(RMWSConsts.LABELS) Set<String> oldNodeLabels,
1180 @Context HttpServletRequest hsr) throws Exception {
1181 init();
1182
1183 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1184 if (callerUGI == null) {
1185 String msg = "Unable to obtain user name, user not authenticated for"
1186 + " post to .../remove-node-labels";
1187 throw new AuthorizationException(msg);
1188 }
1189 if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) {
1190 String msg = "User " + callerUGI.getShortUserName() + " not authorized"
1191 + " for post to .../remove-node-labels ";
1192 throw new AuthorizationException(msg);
1193 }
1194
1195 try {
1196 rm.getRMContext().getNodeLabelManager()
1197 .removeFromClusterNodeLabels(new HashSet<String>(oldNodeLabels));
1198 } catch (IOException e) {
1199 throw new BadRequestException(e);
1200 }
1201
1202 return Response.status(Status.OK).build();
1203 }
1204
1205 @GET
1206 @Path(RMWSConsts.NODES_NODEID_GETLABELS)
1207 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1208 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1209 @Override
1210 public NodeLabelsInfo getLabelsOnNode(@Context HttpServletRequest hsr,
1211 @PathParam(RMWSConsts.NODEID) String nodeId) throws IOException {
1212 init();
1213
1214 NodeId nid = ConverterUtils.toNodeIdWithDefaultPort(nodeId);
1215 List<NodeLabel> labels = new ArrayList<NodeLabel>(
1216 rm.getRMContext().getNodeLabelManager().getLabelsInfoByNode(nid));
1217 return new NodeLabelsInfo(labels);
1218 }
1219
1220 protected Response killApp(RMApp app, UserGroupInformation callerUGI,
1221 HttpServletRequest hsr, String diagnostic)
1222 throws IOException, InterruptedException {
1223
1224 if (app == null) {
1225 throw new IllegalArgumentException("app cannot be null");
1226 }
1227 String userName = callerUGI.getUserName();
1228 final ApplicationId appid = app.getApplicationId();
1229 KillApplicationResponse resp = null;
1230 try {
1231 resp = callerUGI
1232 .doAs(new PrivilegedExceptionAction<KillApplicationResponse>() {
1233 @Override
1234 public KillApplicationResponse run()
1235 throws IOException, YarnException {
1236 KillApplicationRequest req =
1237 KillApplicationRequest.newInstance(appid);
1238 if (diagnostic != null) {
1239 req.setDiagnostics(diagnostic);
1240 }
1241 return rm.getClientRMService().forceKillApplication(req);
1242 }
1243 });
1244 } catch (UndeclaredThrowableException ue) {
1245 // if the root cause is a permissions issue
1246 // bubble that up to the user
1247 if (ue.getCause() instanceof YarnException) {
1248 YarnException ye = (YarnException) ue.getCause();
1249 if (ye.getCause() instanceof AccessControlException) {
1250 String appId = app.getApplicationId().toString();
1251 String msg = "Unauthorized attempt to kill appid " + appId
1252 + " by remote user " + userName;
1253 return Response.status(Status.FORBIDDEN).entity(msg).build();
1254 } else {
1255 throw ue;
1256 }
1257 } else {
1258 throw ue;
1259 }
1260 }
1261
1262 AppState ret = new AppState();
1263 ret.setState(app.getState().toString());
1264
1265 if (resp.getIsKillCompleted()) {
1266 RMAuditLogger.logSuccess(userName, AuditConstants.KILL_APP_REQUEST,
1267 "RMWebService", app.getApplicationId());
1268 } else {
1269 return Response.status(Status.ACCEPTED).entity(ret)
1270 .header(HttpHeaders.LOCATION, hsr.getRequestURL()).build();
1271 }
1272 return Response.status(Status.OK).entity(ret).build();
1273 }
1274
1275 @GET
1276 @Path(RMWSConsts.APPS_APPID_PRIORITY)
1277 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1278 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1279 @Override
1280 public AppPriority getAppPriority(@Context HttpServletRequest hsr,
1281 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException {
1282 init();
1283 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1284 String userName = "UNKNOWN-USER";
1285 if (callerUGI != null) {
1286 userName = callerUGI.getUserName();
1287 }
1288 RMApp app = null;
1289 try {
1290 app = getRMAppForAppId(appId);
1291 } catch (NotFoundException e) {
1292 RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_PRIORITY,
1293 "UNKNOWN", "RMWebService",
1294 "Trying to get priority of an absent application " + appId);
1295 throw e;
1296 }
1297
1298 AppPriority ret = new AppPriority();
1299 ret.setPriority(app.getApplicationPriority().getPriority());
1300
1301 return ret;
1302 }
1303
1304 @PUT
1305 @Path(RMWSConsts.APPS_APPID_PRIORITY)
1306 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1307 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1308 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
1309 @Override
1310 public Response updateApplicationPriority(AppPriority targetPriority,
1311 @Context HttpServletRequest hsr,
1312 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException,
1313 YarnException, InterruptedException, IOException {
1314 init();
1315 if (targetPriority == null) {
1316 throw new YarnException("Target Priority cannot be null");
1317 }
1318
1319 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1320 if (callerUGI == null) {
1321 throw new AuthorizationException(
1322 "Unable to obtain user name, user not authenticated");
1323 }
1324
1325 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
1326 return Response.status(Status.FORBIDDEN)
1327 .entity("The default static user cannot carry out this operation.")
1328 .build();
1329 }
1330
1331 String userName = callerUGI.getUserName();
1332 RMApp app = null;
1333 try {
1334 app = getRMAppForAppId(appId);
1335 } catch (NotFoundException e) {
1336 RMAuditLogger.logFailure(userName, AuditConstants.UPDATE_APP_PRIORITY,
1337 "UNKNOWN", "RMWebService",
1338 "Trying to update priority an absent application " + appId);
1339 throw e;
1340 }
1341 Priority priority = app.getApplicationPriority();
1342 if (priority == null
1343 || priority.getPriority() != targetPriority.getPriority()) {
1344 return modifyApplicationPriority(app, callerUGI,
1345 targetPriority.getPriority());
1346 }
1347 return Response.status(Status.OK).entity(targetPriority).build();
1348 }
1349
1350 private Response modifyApplicationPriority(final RMApp app,
1351 UserGroupInformation callerUGI, final int appPriority)
1352 throws IOException, InterruptedException {
1353 String userName = callerUGI.getUserName();
1354 try {
1355 callerUGI.doAs(new PrivilegedExceptionAction<Void>() {
1356 @Override
1357 public Void run() throws IOException, YarnException {
1358 Priority priority = Priority.newInstance(appPriority);
1359 UpdateApplicationPriorityRequest request =
1360 UpdateApplicationPriorityRequest
1361 .newInstance(app.getApplicationId(), priority);
1362 rm.getClientRMService().updateApplicationPriority(request);
1363 return null;
1364 }
1365 });
1366 } catch (UndeclaredThrowableException ue) {
1367 // if the root cause is a permissions issue
1368 // bubble that up to the user
1369 if (ue.getCause() instanceof YarnException) {
1370 YarnException ye = (YarnException) ue.getCause();
1371 if (ye.getCause() instanceof AccessControlException) {
1372 String appId = app.getApplicationId().toString();
1373 String msg = "Unauthorized attempt to change priority of appid "
1374 + appId + " by remote user " + userName;
1375 return Response.status(Status.FORBIDDEN).entity(msg).build();
1376 } else if (ye.getMessage().startsWith("Application in")
1377 && ye.getMessage().endsWith("state cannot be update priority.")) {
1378 return Response.status(Status.BAD_REQUEST).entity(ye.getMessage())
1379 .build();
1380 } else {
1381 throw ue;
1382 }
1383 } else {
1384 throw ue;
1385 }
1386 }
1387 AppPriority ret =
1388 new AppPriority(app.getApplicationPriority().getPriority());
1389 return Response.status(Status.OK).entity(ret).build();
1390 }
1391
1392 @GET
1393 @Path(RMWSConsts.APPS_APPID_QUEUE)
1394 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1395 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1396 @Override
1397 public AppQueue getAppQueue(@Context HttpServletRequest hsr,
1398 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException {
1399 init();
1400 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1401 String userName = "UNKNOWN-USER";
1402 if (callerUGI != null) {
1403 userName = callerUGI.getUserName();
1404 }
1405 RMApp app = null;
1406 try {
1407 app = getRMAppForAppId(appId);
1408 } catch (NotFoundException e) {
1409 RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_QUEUE,
1410 "UNKNOWN", "RMWebService",
1411 "Trying to get queue of an absent application " + appId);
1412 throw e;
1413 }
1414
1415 AppQueue ret = new AppQueue();
1416 ret.setQueue(app.getQueue());
1417
1418 return ret;
1419 }
1420
1421 @PUT
1422 @Path(RMWSConsts.APPS_APPID_QUEUE)
1423 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1424 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1425 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
1426 @Override
1427 public Response updateAppQueue(AppQueue targetQueue,
1428 @Context HttpServletRequest hsr,
1429 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException,
1430 YarnException, InterruptedException, IOException {
1431
1432 init();
1433 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1434 if (callerUGI == null) {
1435 String msg = "Unable to obtain user name, user not authenticated";
1436 throw new AuthorizationException(msg);
1437 }
1438
1439 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
1440 String msg = "The default static user cannot carry out this operation.";
1441 return Response.status(Status.FORBIDDEN).entity(msg).build();
1442 }
1443
1444 String userName = callerUGI.getUserName();
1445 RMApp app = null;
1446 try {
1447 app = getRMAppForAppId(appId);
1448 } catch (NotFoundException e) {
1449 RMAuditLogger.logFailure(userName, AuditConstants.MOVE_APP_REQUEST,
1450 "UNKNOWN", "RMWebService",
1451 "Trying to move an absent application " + appId);
1452 throw e;
1453 }
1454
1455 if (!app.getQueue().equals(targetQueue.getQueue())) {
1456 // user is attempting to change queue.
1457 return moveApp(app, callerUGI, targetQueue.getQueue());
1458 }
1459
1460 AppQueue ret = new AppQueue();
1461 ret.setQueue(app.getQueue());
1462
1463 return Response.status(Status.OK).entity(ret).build();
1464 }
1465
1466 protected Response moveApp(RMApp app, UserGroupInformation callerUGI,
1467 String targetQueue) throws IOException, InterruptedException {
1468
1469 if (app == null) {
1470 throw new IllegalArgumentException("app cannot be null");
1471 }
1472 String userName = callerUGI.getUserName();
1473 final ApplicationId appid = app.getApplicationId();
1474 final String reqTargetQueue = targetQueue;
1475 try {
1476 callerUGI.doAs(new PrivilegedExceptionAction<Void>() {
1477 @Override
1478 public Void run() throws IOException, YarnException {
1479 MoveApplicationAcrossQueuesRequest req =
1480 MoveApplicationAcrossQueuesRequest.newInstance(appid,
1481 reqTargetQueue);
1482 rm.getClientRMService().moveApplicationAcrossQueues(req);
1483 return null;
1484 }
1485 });
1486 } catch (UndeclaredThrowableException ue) {
1487 // if the root cause is a permissions issue
1488 // bubble that up to the user
1489 if (ue.getCause() instanceof YarnException) {
1490 YarnException ye = (YarnException) ue.getCause();
1491 if (ye.getCause() instanceof AccessControlException) {
1492 String appId = app.getApplicationId().toString();
1493 String msg = "Unauthorized attempt to move appid " + appId
1494 + " by remote user " + userName;
1495 return Response.status(Status.FORBIDDEN).entity(msg).build();
1496 } else if (ye.getMessage().startsWith("App in")
1497 && ye.getMessage().endsWith("state cannot be moved.")) {
1498 return Response.status(Status.BAD_REQUEST).entity(ye.getMessage())
1499 .build();
1500 } else {
1501 throw ue;
1502 }
1503 } else {
1504 throw ue;
1505 }
1506 }
1507
1508 AppQueue ret = new AppQueue();
1509 ret.setQueue(app.getQueue());
1510 return Response.status(Status.OK).entity(ret).build();
1511 }
1512
1513 private RMApp getRMAppForAppId(String appId) {
1514 ApplicationId id = WebAppUtils.parseApplicationId(recordFactory, appId);
1515 RMApp app = rm.getRMContext().getRMApps().get(id);
1516 if (app == null) {
1517 throw new NotFoundException("app with id: " + appId + " not found");
1518 }
1519 return app;
1520 }
1521
1522 private UserGroupInformation getCallerUserGroupInformation(
1523 HttpServletRequest hsr, boolean usePrincipal) {
1524
1525 String remoteUser = hsr.getRemoteUser();
1526 if (usePrincipal) {
1527 Principal princ = hsr.getUserPrincipal();
1528 remoteUser = princ == null ? null : princ.getName();
1529 }
1530
1531 UserGroupInformation callerUGI = null;
1532 if (remoteUser != null) {
1533 callerUGI = UserGroupInformation.createRemoteUser(remoteUser);
1534 }
1535
1536 return callerUGI;
1537 }
1538
1539 private boolean isStaticUser(UserGroupInformation callerUGI) {
1540 String staticUser =
1541 conf.get(CommonConfigurationKeys.HADOOP_HTTP_STATIC_USER,
1542 CommonConfigurationKeys.DEFAULT_HADOOP_HTTP_STATIC_USER);
1543 return staticUser.equals(callerUGI.getUserName());
1544 }
1545
1546 @POST
1547 @Path(RMWSConsts.APPS_NEW_APPLICATION)
1548 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1549 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1550 @Override
1551 public Response createNewApplication(@Context HttpServletRequest hsr)
1552 throws AuthorizationException, IOException, InterruptedException {
1553 init();
1554 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1555 if (callerUGI == null) {
1556 throw new AuthorizationException(
1557 "Unable to obtain user name, " + "user not authenticated");
1558 }
1559 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
1560 String msg = "The default static user cannot carry out this operation.";
1561 return Response.status(Status.FORBIDDEN).entity(msg).build();
1562 }
1563
1564 NewApplication appId = createNewApplication();
1565 return Response.status(Status.OK).entity(appId).build();
1566
1567 }
1568
1569 // reuse the code in ClientRMService to create new app
1570 // get the new app id and submit app
1571 // set location header with new app location
1572 @POST
1573 @Path(RMWSConsts.APPS)
1574 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1575 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1576 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
1577 @Override
1578 public Response submitApplication(ApplicationSubmissionContextInfo newApp,
1579 @Context HttpServletRequest hsr)
1580 throws AuthorizationException, IOException, InterruptedException {
1581
1582 init();
1583 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1584 if (callerUGI == null) {
1585 throw new AuthorizationException(
1586 "Unable to obtain user name, " + "user not authenticated");
1587 }
1588
1589 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
1590 String msg = "The default static user cannot carry out this operation.";
1591 return Response.status(Status.FORBIDDEN).entity(msg).build();
1592 }
1593
1594 ApplicationSubmissionContext appContext =
1595 RMWebAppUtil.createAppSubmissionContext(newApp, conf);
1596
1597 final SubmitApplicationRequest req =
1598 SubmitApplicationRequest.newInstance(appContext);
1599
1600 try {
1601 callerUGI
1602 .doAs(new PrivilegedExceptionAction<SubmitApplicationResponse>() {
1603 @Override
1604 public SubmitApplicationResponse run()
1605 throws IOException, YarnException {
1606 return rm.getClientRMService().submitApplication(req);
1607 }
1608 });
1609 } catch (UndeclaredThrowableException ue) {
1610 if (ue.getCause() instanceof YarnException) {
1611 throw new BadRequestException(ue.getCause().getMessage());
1612 }
1613 LOG.info("Submit app request failed", ue);
1614 throw ue;
1615 }
1616
1617 String url = hsr.getRequestURL() + "/" + newApp.getApplicationId();
1618 return Response.status(Status.ACCEPTED).header(HttpHeaders.LOCATION, url)
1619 .build();
1620 }
1621
1622 /**
1623 * Function that actually creates the ApplicationId by calling the
1624 * ClientRMService
1625 *
1626 * @return returns structure containing the app-id and maximum resource
1627 * capabilities
1628 */
1629 private NewApplication createNewApplication() {
1630 GetNewApplicationRequest req =
1631 recordFactory.newRecordInstance(GetNewApplicationRequest.class);
1632 GetNewApplicationResponse resp;
1633 try {
1634 resp = rm.getClientRMService().getNewApplication(req);
1635 } catch (YarnException e) {
1636 String msg = "Unable to create new app from RM web service";
1637 LOG.error(msg, e);
1638 throw new YarnRuntimeException(msg, e);
1639 }
1640 NewApplication appId =
1641 new NewApplication(resp.getApplicationId().toString(),
1642 new ResourceInfo(resp.getMaximumResourceCapability()));
1643 return appId;
1644 }
1645
1646 private UserGroupInformation createKerberosUserGroupInformation(
1647 HttpServletRequest hsr) throws AuthorizationException, YarnException {
1648
1649 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1650 if (callerUGI == null) {
1651 String msg = "Unable to obtain user name, user not authenticated";
1652 throw new AuthorizationException(msg);
1653 }
1654
1655 String authType = hsr.getAuthType();
1656 if (!KerberosAuthenticationHandler.TYPE.equalsIgnoreCase(authType)) {
1657 String msg = "Delegation token operations can only be carried out on a "
1658 + "Kerberos authenticated channel. Expected auth type is "
1659 + KerberosAuthenticationHandler.TYPE + ", got type " + authType;
1660 throw new YarnException(msg);
1661 }
1662 if (hsr.getAttribute(
1663 DelegationTokenAuthenticationHandler.DELEGATION_TOKEN_UGI_ATTRIBUTE) != null) {
1664 String msg =
1665 "Delegation token operations cannot be carried out using delegation"
1666 + " token authentication.";
1667 throw new YarnException(msg);
1668 }
1669
1670 callerUGI.setAuthenticationMethod(AuthenticationMethod.KERBEROS);
1671 return callerUGI;
1672 }
1673
1674 @POST
1675 @Path(RMWSConsts.DELEGATION_TOKEN)
1676 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1677 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1678 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
1679 @Override
1680 public Response postDelegationToken(DelegationToken tokenData,
1681 @Context HttpServletRequest hsr) throws AuthorizationException,
1682 IOException, InterruptedException, Exception {
1683
1684 init();
1685 UserGroupInformation callerUGI;
1686 try {
1687 callerUGI = createKerberosUserGroupInformation(hsr);
1688 } catch (YarnException ye) {
1689 return Response.status(Status.FORBIDDEN).entity(ye.getMessage()).build();
1690 }
1691 return createDelegationToken(tokenData, hsr, callerUGI);
1692 }
1693
1694 @POST
1695 @Path(RMWSConsts.DELEGATION_TOKEN_EXPIRATION)
1696 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1697 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1698 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
1699 @Override
1700 public Response postDelegationTokenExpiration(@Context HttpServletRequest hsr)
1701 throws AuthorizationException, IOException, InterruptedException,
1702 Exception {
1703
1704 init();
1705 UserGroupInformation callerUGI;
1706 try {
1707 callerUGI = createKerberosUserGroupInformation(hsr);
1708 } catch (YarnException ye) {
1709 return Response.status(Status.FORBIDDEN).entity(ye.getMessage()).build();
1710 }
1711
1712 DelegationToken requestToken = new DelegationToken();
1713 requestToken.setToken(extractToken(hsr).encodeToUrlString());
1714 return renewDelegationToken(requestToken, hsr, callerUGI);
1715 }
1716
1717 private Response createDelegationToken(DelegationToken tokenData,
1718 HttpServletRequest hsr, UserGroupInformation callerUGI)
1719 throws AuthorizationException, IOException, InterruptedException,
1720 Exception {
1721
1722 final String renewer = tokenData.getRenewer();
1723 GetDelegationTokenResponse resp;
1724 try {
1725 resp = callerUGI
1726 .doAs(new PrivilegedExceptionAction<GetDelegationTokenResponse>() {
1727 @Override
1728 public GetDelegationTokenResponse run()
1729 throws IOException, YarnException {
1730 GetDelegationTokenRequest createReq =
1731 GetDelegationTokenRequest.newInstance(renewer);
1732 return rm.getClientRMService().getDelegationToken(createReq);
1733 }
1734 });
1735 } catch (Exception e) {
1736 LOG.info("Create delegation token request failed", e);
1737 throw e;
1738 }
1739
1740 Token<RMDelegationTokenIdentifier> tk =
1741 new Token<RMDelegationTokenIdentifier>(
1742 resp.getRMDelegationToken().getIdentifier().array(),
1743 resp.getRMDelegationToken().getPassword().array(),
1744 new Text(resp.getRMDelegationToken().getKind()),
1745 new Text(resp.getRMDelegationToken().getService()));
1746 RMDelegationTokenIdentifier identifier = tk.decodeIdentifier();
1747 long currentExpiration = rm.getRMContext()
1748 .getRMDelegationTokenSecretManager().getRenewDate(identifier);
1749 DelegationToken respToken = new DelegationToken(tk.encodeToUrlString(),
1750 renewer, identifier.getOwner().toString(), tk.getKind().toString(),
1751 currentExpiration, identifier.getMaxDate());
1752 return Response.status(Status.OK).entity(respToken).build();
1753 }
1754
1755 private Response renewDelegationToken(DelegationToken tokenData,
1756 HttpServletRequest hsr, UserGroupInformation callerUGI)
1757 throws AuthorizationException, IOException, InterruptedException,
1758 Exception {
1759
1760 Token<RMDelegationTokenIdentifier> token =
1761 extractToken(tokenData.getToken());
1762
1763 org.apache.hadoop.yarn.api.records.Token dToken = BuilderUtils
1764 .newDelegationToken(token.getIdentifier(), token.getKind().toString(),
1765 token.getPassword(), token.getService().toString());
1766 final RenewDelegationTokenRequest req =
1767 RenewDelegationTokenRequest.newInstance(dToken);
1768
1769 RenewDelegationTokenResponse resp;
1770 try {
1771 resp = callerUGI
1772 .doAs(new PrivilegedExceptionAction<RenewDelegationTokenResponse>() {
1773 @Override
1774 public RenewDelegationTokenResponse run() throws YarnException {
1775 return rm.getClientRMService().renewDelegationToken(req);
1776 }
1777 });
1778 } catch (UndeclaredThrowableException ue) {
1779 if (ue.getCause() instanceof YarnException) {
1780 if (ue.getCause().getCause() instanceof InvalidToken) {
1781 throw new BadRequestException(ue.getCause().getCause().getMessage());
1782 } else if (ue.getCause()
1783 .getCause() instanceof org.apache.hadoop.security.AccessControlException) {
1784 return Response.status(Status.FORBIDDEN)
1785 .entity(ue.getCause().getCause().getMessage()).build();
1786 }
1787 LOG.info("Renew delegation token request failed", ue);
1788 throw ue;
1789 }
1790 LOG.info("Renew delegation token request failed", ue);
1791 throw ue;
1792 } catch (Exception e) {
1793 LOG.info("Renew delegation token request failed", e);
1794 throw e;
1795 }
1796 long renewTime = resp.getNextExpirationTime();
1797
1798 DelegationToken respToken = new DelegationToken();
1799 respToken.setNextExpirationTime(renewTime);
1800 return Response.status(Status.OK).entity(respToken).build();
1801 }
1802
1803 // For cancelling tokens, the encoded token is passed as a header
1804 // There are two reasons for this -
1805 // 1. Passing a request body as part of a DELETE request is not
1806 // allowed by Jetty
1807 // 2. Passing the encoded token as part of the url is not ideal
1808 // since urls tend to get logged and anyone with access to
1809 // the logs can extract tokens which are meant to be secret
1810 @DELETE
1811 @Path(RMWSConsts.DELEGATION_TOKEN)
1812 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1813 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1814 @Override
1815 public Response cancelDelegationToken(@Context HttpServletRequest hsr)
1816 throws AuthorizationException, IOException, InterruptedException,
1817 Exception {
1818
1819 init();
1820 UserGroupInformation callerUGI;
1821 try {
1822 callerUGI = createKerberosUserGroupInformation(hsr);
1823 } catch (YarnException ye) {
1824 return Response.status(Status.FORBIDDEN).entity(ye.getMessage()).build();
1825 }
1826
1827 Token<RMDelegationTokenIdentifier> token = extractToken(hsr);
1828
1829 org.apache.hadoop.yarn.api.records.Token dToken = BuilderUtils
1830 .newDelegationToken(token.getIdentifier(), token.getKind().toString(),
1831 token.getPassword(), token.getService().toString());
1832 final CancelDelegationTokenRequest req =
1833 CancelDelegationTokenRequest.newInstance(dToken);
1834
1835 try {
1836 callerUGI
1837 .doAs(new PrivilegedExceptionAction<CancelDelegationTokenResponse>() {
1838 @Override
1839 public CancelDelegationTokenResponse run()
1840 throws IOException, YarnException {
1841 return rm.getClientRMService().cancelDelegationToken(req);
1842 }
1843 });
1844 } catch (UndeclaredThrowableException ue) {
1845 if (ue.getCause() instanceof YarnException) {
1846 if (ue.getCause().getCause() instanceof InvalidToken) {
1847 throw new BadRequestException(ue.getCause().getCause().getMessage());
1848 } else if (ue.getCause()
1849 .getCause() instanceof org.apache.hadoop.security.AccessControlException) {
1850 return Response.status(Status.FORBIDDEN)
1851 .entity(ue.getCause().getCause().getMessage()).build();
1852 }
1853 LOG.info("Renew delegation token request failed", ue);
1854 throw ue;
1855 }
1856 LOG.info("Renew delegation token request failed", ue);
1857 throw ue;
1858 } catch (Exception e) {
1859 LOG.info("Renew delegation token request failed", e);
1860 throw e;
1861 }
1862
1863 return Response.status(Status.OK).build();
1864 }
1865
1866 private Token<RMDelegationTokenIdentifier> extractToken(
1867 HttpServletRequest request) {
1868 String encodedToken = request.getHeader(DELEGATION_TOKEN_HEADER);
1869 if (encodedToken == null) {
1870 String msg = "Header '" + DELEGATION_TOKEN_HEADER
1871 + "' containing encoded token not found";
1872 throw new BadRequestException(msg);
1873 }
1874 return extractToken(encodedToken);
1875 }
1876
1877 private Token<RMDelegationTokenIdentifier> extractToken(String encodedToken) {
1878 Token<RMDelegationTokenIdentifier> token =
1879 new Token<RMDelegationTokenIdentifier>();
1880 try {
1881 token.decodeFromUrlString(encodedToken);
1882 } catch (Exception ie) {
1883 String msg = "Could not decode encoded token";
1884 throw new BadRequestException(msg);
1885 }
1886 return token;
1887 }
1888
1889 @POST
1890 @Path(RMWSConsts.RESERVATION_NEW)
1891 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1892 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1893 @Override
1894 public Response createNewReservation(@Context HttpServletRequest hsr)
1895 throws AuthorizationException, IOException, InterruptedException {
1896 init();
1897 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1898 if (callerUGI == null) {
1899 throw new AuthorizationException(
1900 "Unable to obtain user name, " + "user not authenticated");
1901 }
1902 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
1903 String msg = "The default static user cannot carry out this operation.";
1904 return Response.status(Status.FORBIDDEN).entity(msg).build();
1905 }
1906
1907 NewReservation reservationId = createNewReservation();
1908 return Response.status(Status.OK).entity(reservationId).build();
1909
1910 }
1911
1912 /**
1913 * Function that actually creates the {@link ReservationId} by calling the
1914 * ClientRMService.
1915 *
1916 * @return returns structure containing the {@link ReservationId}
1917 * @throws IOException if creation fails.
1918 */
1919 private NewReservation createNewReservation() throws IOException {
1920 GetNewReservationRequest req =
1921 recordFactory.newRecordInstance(GetNewReservationRequest.class);
1922 GetNewReservationResponse resp;
1923 try {
1924 resp = rm.getClientRMService().getNewReservation(req);
1925 } catch (YarnException e) {
1926 String msg = "Unable to create new reservation from RM web service";
1927 LOG.error(msg, e);
1928 throw new YarnRuntimeException(msg, e);
1929 }
1930 NewReservation reservationId =
1931 new NewReservation(resp.getReservationId().toString());
1932 return reservationId;
1933 }
1934
1935 @POST
1936 @Path(RMWSConsts.RESERVATION_SUBMIT)
1937 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
1938 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
1939 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
1940 @Override
1941 public Response submitReservation(ReservationSubmissionRequestInfo resContext,
1942 @Context HttpServletRequest hsr)
1943 throws AuthorizationException, IOException, InterruptedException {
1944
1945 init();
1946 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
1947 if (callerUGI == null) {
1948 throw new AuthorizationException(
1949 "Unable to obtain user name, " + "user not authenticated");
1950 }
1951 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
1952 String msg = "The default static user cannot carry out this operation.";
1953 return Response.status(Status.FORBIDDEN).entity(msg).build();
1954 }
1955
1956 final ReservationSubmissionRequest reservation =
1957 createReservationSubmissionRequest(resContext);
1958
1959 try {
1960 callerUGI
1961 .doAs(new PrivilegedExceptionAction<ReservationSubmissionResponse>() {
1962 @Override
1963 public ReservationSubmissionResponse run()
1964 throws IOException, YarnException {
1965 return rm.getClientRMService().submitReservation(reservation);
1966 }
1967 });
1968 } catch (UndeclaredThrowableException ue) {
1969 if (ue.getCause() instanceof YarnException) {
1970 throw new BadRequestException(ue.getCause().getMessage());
1971 }
1972 LOG.info("Submit reservation request failed", ue);
1973 throw ue;
1974 }
1975
1976 return Response.status(Status.ACCEPTED).build();
1977 }
1978
1979 private ReservationSubmissionRequest createReservationSubmissionRequest(
1980 ReservationSubmissionRequestInfo resContext) throws IOException {
1981
1982 // defending against a couple of common submission format problems
1983 if (resContext == null) {
1984 throw new BadRequestException(
1985 "Input ReservationSubmissionContext should not be null");
1986 }
1987 ReservationDefinitionInfo resInfo = resContext.getReservationDefinition();
1988 if (resInfo == null) {
1989 throw new BadRequestException(
1990 "Input ReservationDefinition should not be null");
1991 }
1992
1993 ReservationRequestsInfo resReqsInfo = resInfo.getReservationRequests();
1994
1995 if (resReqsInfo == null || resReqsInfo.getReservationRequest() == null
1996 || resReqsInfo.getReservationRequest().size() == 0) {
1997 throw new BadRequestException("The ReservationDefinition should"
1998 + " contain at least one ReservationRequest");
1999 }
2000
2001 ReservationRequestInterpreter[] values =
2002 ReservationRequestInterpreter.values();
2003 ReservationRequestInterpreter resInt =
2004 values[resReqsInfo.getReservationRequestsInterpreter()];
2005 List<ReservationRequest> list = new ArrayList<ReservationRequest>();
2006
2007 for (ReservationRequestInfo resReqInfo : resReqsInfo
2008 .getReservationRequest()) {
2009 ResourceInfo rInfo = resReqInfo.getCapability();
2010 Resource capability =
2011 Resource.newInstance(rInfo.getMemorySize(), rInfo.getvCores());
2012 int numContainers = resReqInfo.getNumContainers();
2013 int minConcurrency = resReqInfo.getMinConcurrency();
2014 long duration = resReqInfo.getDuration();
2015 ReservationRequest rr = ReservationRequest.newInstance(capability,
2016 numContainers, minConcurrency, duration);
2017 list.add(rr);
2018 }
2019 ReservationRequests reqs = ReservationRequests.newInstance(list, resInt);
2020 ReservationDefinition rDef = ReservationDefinition.newInstance(
2021 resInfo.getArrival(), resInfo.getDeadline(), reqs,
2022 resInfo.getReservationName(), resInfo.getRecurrenceExpression(),
2023 Priority.newInstance(resInfo.getPriority()));
2024
2025 ReservationId reservationId =
2026 ReservationId.parseReservationId(resContext.getReservationId());
2027 ReservationSubmissionRequest request = ReservationSubmissionRequest
2028 .newInstance(rDef, resContext.getQueue(), reservationId);
2029
2030 return request;
2031 }
2032
2033 @POST
2034 @Path(RMWSConsts.RESERVATION_UPDATE)
2035 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
2036 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
2037 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
2038 @Override
2039 public Response updateReservation(ReservationUpdateRequestInfo resContext,
2040 @Context HttpServletRequest hsr)
2041 throws AuthorizationException, IOException, InterruptedException {
2042
2043 init();
2044 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
2045 if (callerUGI == null) {
2046 throw new AuthorizationException(
2047 "Unable to obtain user name, " + "user not authenticated");
2048 }
2049 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
2050 String msg = "The default static user cannot carry out this operation.";
2051 return Response.status(Status.FORBIDDEN).entity(msg).build();
2052 }
2053
2054 final ReservationUpdateRequest reservation =
2055 createReservationUpdateRequest(resContext);
2056
2057 ReservationUpdateResponseInfo resRespInfo;
2058 try {
2059 resRespInfo = callerUGI
2060 .doAs(new PrivilegedExceptionAction<ReservationUpdateResponseInfo>() {
2061 @Override
2062 public ReservationUpdateResponseInfo run()
2063 throws IOException, YarnException {
2064 rm.getClientRMService().updateReservation(reservation);
2065 return new ReservationUpdateResponseInfo();
2066 }
2067 });
2068 } catch (UndeclaredThrowableException ue) {
2069 if (ue.getCause() instanceof YarnException) {
2070 throw new BadRequestException(ue.getCause().getMessage());
2071 }
2072 LOG.info("Update reservation request failed", ue);
2073 throw ue;
2074 }
2075
2076 return Response.status(Status.OK).entity(resRespInfo).build();
2077 }
2078
2079 private ReservationUpdateRequest createReservationUpdateRequest(
2080 ReservationUpdateRequestInfo resContext) throws IOException {
2081
2082 // defending against a couple of common submission format problems
2083 if (resContext == null) {
2084 throw new BadRequestException(
2085 "Input ReservationSubmissionContext should not be null");
2086 }
2087 ReservationDefinitionInfo resInfo = resContext.getReservationDefinition();
2088 if (resInfo == null) {
2089 throw new BadRequestException(
2090 "Input ReservationDefinition should not be null");
2091 }
2092 ReservationRequestsInfo resReqsInfo = resInfo.getReservationRequests();
2093 if (resReqsInfo == null || resReqsInfo.getReservationRequest() == null
2094 || resReqsInfo.getReservationRequest().size() == 0) {
2095 throw new BadRequestException("The ReservationDefinition should"
2096 + " contain at least one ReservationRequest");
2097 }
2098 if (resContext.getReservationId() == null) {
2099 throw new BadRequestException(
2100 "Update operations must specify an existing ReservaitonId");
2101 }
2102
2103 ReservationRequestInterpreter[] values =
2104 ReservationRequestInterpreter.values();
2105 ReservationRequestInterpreter resInt =
2106 values[resReqsInfo.getReservationRequestsInterpreter()];
2107 List<ReservationRequest> list = new ArrayList<ReservationRequest>();
2108
2109 for (ReservationRequestInfo resReqInfo : resReqsInfo
2110 .getReservationRequest()) {
2111 ResourceInfo rInfo = resReqInfo.getCapability();
2112 Resource capability =
2113 Resource.newInstance(rInfo.getMemorySize(), rInfo.getvCores());
2114 int numContainers = resReqInfo.getNumContainers();
2115 int minConcurrency = resReqInfo.getMinConcurrency();
2116 long duration = resReqInfo.getDuration();
2117 ReservationRequest rr = ReservationRequest.newInstance(capability,
2118 numContainers, minConcurrency, duration);
2119 list.add(rr);
2120 }
2121 ReservationRequests reqs = ReservationRequests.newInstance(list, resInt);
2122 ReservationDefinition rDef = ReservationDefinition.newInstance(
2123 resInfo.getArrival(), resInfo.getDeadline(), reqs,
2124 resInfo.getReservationName(), resInfo.getRecurrenceExpression(),
2125 Priority.newInstance(resInfo.getPriority()));
2126 ReservationUpdateRequest request = ReservationUpdateRequest.newInstance(
2127 rDef, ReservationId.parseReservationId(resContext.getReservationId()));
2128
2129 return request;
2130 }
2131
2132 @POST
2133 @Path(RMWSConsts.RESERVATION_DELETE)
2134 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
2135 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
2136 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
2137 @Override
2138 public Response deleteReservation(ReservationDeleteRequestInfo resContext,
2139 @Context HttpServletRequest hsr)
2140 throws AuthorizationException, IOException, InterruptedException {
2141
2142 init();
2143 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
2144 if (callerUGI == null) {
2145 throw new AuthorizationException(
2146 "Unable to obtain user name, " + "user not authenticated");
2147 }
2148 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
2149 String msg = "The default static user cannot carry out this operation.";
2150 return Response.status(Status.FORBIDDEN).entity(msg).build();
2151 }
2152
2153 final ReservationDeleteRequest reservation =
2154 createReservationDeleteRequest(resContext);
2155
2156 ReservationDeleteResponseInfo resRespInfo;
2157 try {
2158 resRespInfo = callerUGI
2159 .doAs(new PrivilegedExceptionAction<ReservationDeleteResponseInfo>() {
2160 @Override
2161 public ReservationDeleteResponseInfo run()
2162 throws IOException, YarnException {
2163 rm.getClientRMService().deleteReservation(reservation);
2164 return new ReservationDeleteResponseInfo();
2165 }
2166 });
2167 } catch (UndeclaredThrowableException ue) {
2168 if (ue.getCause() instanceof YarnException) {
2169 throw new BadRequestException(ue.getCause().getMessage());
2170 }
2171 LOG.info("Update reservation request failed", ue);
2172 throw ue;
2173 }
2174
2175 return Response.status(Status.OK).entity(resRespInfo).build();
2176 }
2177
2178 private ReservationDeleteRequest createReservationDeleteRequest(
2179 ReservationDeleteRequestInfo resContext) throws IOException {
2180
2181 ReservationDeleteRequest request = ReservationDeleteRequest.newInstance(
2182 ReservationId.parseReservationId(resContext.getReservationId()));
2183
2184 return request;
2185 }
2186
2187 @GET
2188 @Path(RMWSConsts.RESERVATION_LIST)
2189 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
2190 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
2191 @Override
2192 public Response listReservation(
2193 @QueryParam(RMWSConsts.QUEUE) @DefaultValue(DEFAULT_QUEUE) String queue,
2194 @QueryParam(RMWSConsts.RESERVATION_ID) @DefaultValue(DEFAULT_RESERVATION_ID) String reservationId,
2195 @QueryParam(RMWSConsts.START_TIME) @DefaultValue(DEFAULT_START_TIME) long startTime,
2196 @QueryParam(RMWSConsts.END_TIME) @DefaultValue(DEFAULT_END_TIME) long endTime,
2197 @QueryParam(RMWSConsts.INCLUDE_RESOURCE) @DefaultValue(DEFAULT_INCLUDE_RESOURCE) boolean includeResourceAllocations,
2198 @Context HttpServletRequest hsr) throws Exception {
2199 init();
2200
2201 final ReservationListRequest request = ReservationListRequest.newInstance(
2202 queue, reservationId, startTime, endTime, includeResourceAllocations);
2203
2204 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
2205 if (callerUGI == null) {
2206 throw new AuthorizationException(
2207 "Unable to obtain user name, " + "user not authenticated");
2208 }
2209 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
2210 String msg = "The default static user cannot carry out this operation.";
2211 return Response.status(Status.FORBIDDEN).entity(msg).build();
2212 }
2213
2214 ReservationListResponse resRespInfo;
2215 try {
2216 resRespInfo = callerUGI
2217 .doAs(new PrivilegedExceptionAction<ReservationListResponse>() {
2218 @Override
2219 public ReservationListResponse run()
2220 throws IOException, YarnException {
2221 return rm.getClientRMService().listReservations(request);
2222 }
2223 });
2224 } catch (UndeclaredThrowableException ue) {
2225 if (ue.getCause() instanceof YarnException) {
2226 throw new BadRequestException(ue.getCause().getMessage());
2227 }
2228 LOG.info("List reservation request failed", ue);
2229 throw ue;
2230 }
2231
2232 ReservationListInfo resResponse =
2233 new ReservationListInfo(resRespInfo, includeResourceAllocations);
2234 return Response.status(Status.OK).entity(resResponse).build();
2235 }
2236
2237 @GET
2238 @Path(RMWSConsts.APPS_TIMEOUTS_TYPE)
2239 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
2240 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
2241 @Override
2242 public AppTimeoutInfo getAppTimeout(@Context HttpServletRequest hsr,
2243 @PathParam(RMWSConsts.APPID) String appId,
2244 @PathParam(RMWSConsts.TYPE) String type) throws AuthorizationException {
2245 init();
2246 RMApp app = validateAppTimeoutRequest(hsr, appId);
2247
2248 ApplicationTimeoutType appTimeoutType = parseTimeoutType(type);
2249 Long timeoutValue = app.getApplicationTimeouts().get(appTimeoutType);
2250 AppTimeoutInfo timeout =
2251 constructAppTimeoutDao(appTimeoutType, timeoutValue);
2252 return timeout;
2253 }
2254
2255 private RMApp validateAppTimeoutRequest(HttpServletRequest hsr,
2256 String appId) {
2257 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
2258 String userName = "UNKNOWN-USER";
2259 if (callerUGI != null) {
2260 userName = callerUGI.getUserName();
2261 }
2262
2263 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
2264 String msg = "The default static user cannot carry out this operation.";
2265 RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_TIMEOUTS,
2266 "UNKNOWN", "RMWebService", msg);
2267 throw new ForbiddenException(msg);
2268 }
2269
2270 RMApp app = null;
2271 try {
2272 app = getRMAppForAppId(appId);
2273 } catch (NotFoundException e) {
2274 RMAuditLogger.logFailure(userName, AuditConstants.GET_APP_TIMEOUTS,
2275 "UNKNOWN", "RMWebService",
2276 "Trying to get timeouts of an absent application " + appId);
2277 throw e;
2278 }
2279 return app;
2280 }
2281
2282 @GET
2283 @Path(RMWSConsts.APPS_TIMEOUTS)
2284 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
2285 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
2286 @Override
2287 public AppTimeoutsInfo getAppTimeouts(@Context HttpServletRequest hsr,
2288 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException {
2289 init();
2290
2291 RMApp app = validateAppTimeoutRequest(hsr, appId);
2292
2293 AppTimeoutsInfo timeouts = new AppTimeoutsInfo();
2294 Map<ApplicationTimeoutType, Long> applicationTimeouts =
2295 app.getApplicationTimeouts();
2296 if (applicationTimeouts.isEmpty()) {
2297 // If application is not set timeout, lifetime should be sent as default
2298 // with expiryTime=UNLIMITED and remainingTime=-1
2299 timeouts
2300 .add(constructAppTimeoutDao(ApplicationTimeoutType.LIFETIME, null));
2301 } else {
2302 for (Entry<ApplicationTimeoutType, Long> timeout : app
2303 .getApplicationTimeouts().entrySet()) {
2304 AppTimeoutInfo timeoutInfo =
2305 constructAppTimeoutDao(timeout.getKey(), timeout.getValue());
2306 timeouts.add(timeoutInfo);
2307 }
2308 }
2309 return timeouts;
2310 }
2311
2312 private ApplicationTimeoutType parseTimeoutType(String type) {
2313 try {
2314 // enum string is in the uppercase
2315 return ApplicationTimeoutType
2316 .valueOf(StringUtils.toUpperCase(type.trim()));
2317 } catch (RuntimeException e) {
2318 ApplicationTimeoutType[] typeArray = ApplicationTimeoutType.values();
2319 String allAppTimeoutTypes = Arrays.toString(typeArray);
2320 throw new BadRequestException("Invalid application-state " + type.trim()
2321 + " specified. It should be one of " + allAppTimeoutTypes);
2322 }
2323 }
2324
2325 private AppTimeoutInfo constructAppTimeoutDao(ApplicationTimeoutType type,
2326 Long timeoutInMillis) {
2327 AppTimeoutInfo timeout = new AppTimeoutInfo();
2328 timeout.setTimeoutType(type);
2329 if (timeoutInMillis != null) {
2330 timeout.setExpiryTime(Times.formatISO8601(timeoutInMillis.longValue()));
2331 timeout.setRemainingTime(
2332 Math.max((timeoutInMillis - System.currentTimeMillis()) / 1000, 0));
2333 }
2334 return timeout;
2335 }
2336
2337 @PUT
2338 @Path(RMWSConsts.APPS_TIMEOUT)
2339 @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
2340 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
2341 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
2342 @Override
2343 public Response updateApplicationTimeout(AppTimeoutInfo appTimeout,
2344 @Context HttpServletRequest hsr,
2345 @PathParam(RMWSConsts.APPID) String appId) throws AuthorizationException,
2346 YarnException, InterruptedException, IOException {
2347 init();
2348
2349 UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
2350 if (callerUGI == null) {
2351 throw new AuthorizationException(
2352 "Unable to obtain user name, user not authenticated");
2353 }
2354
2355 if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) {
2356 return Response.status(Status.FORBIDDEN)
2357 .entity("The default static user cannot carry out this operation.")
2358 .build();
2359 }
2360
2361 String userName = callerUGI.getUserName();
2362 RMApp app = null;
2363 try {
2364 app = getRMAppForAppId(appId);
2365 } catch (NotFoundException e) {
2366 RMAuditLogger.logFailure(userName, AuditConstants.UPDATE_APP_TIMEOUTS,
2367 "UNKNOWN", "RMWebService",
2368 "Trying to update timeout of an absent application " + appId);
2369 throw e;
2370 }
2371
2372 return updateApplicationTimeouts(app, callerUGI, appTimeout);
2373 }
2374
2375 private Response updateApplicationTimeouts(final RMApp app,
2376 UserGroupInformation callerUGI, final AppTimeoutInfo appTimeout)
2377 throws IOException, InterruptedException {
2378 if (appTimeout.getTimeoutType() == null
2379 || appTimeout.getExpireTime() == null) {
2380 return Response.status(Status.BAD_REQUEST)
2381 .entity("Timeout type or ExpiryTime is null.").build();
2382 }