| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hadoop.yarn.server.webapp; |
| |
| import static org.apache.hadoop.yarn.util.StringHelper.join; |
| import static org.apache.hadoop.yarn.webapp.YarnWebParams.APP_STATE; |
| import static org.apache.hadoop.yarn.webapp.YarnWebParams.APP_START_TIME_BEGIN; |
| import static org.apache.hadoop.yarn.webapp.YarnWebParams.APP_START_TIME_END; |
| import static org.apache.hadoop.yarn.webapp.YarnWebParams.APPS_NUM; |
| import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR; |
| import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR_VALUE; |
| |
| import java.io.IOException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.Collection; |
| import java.util.EnumSet; |
| |
| import org.apache.commons.lang.StringEscapeUtils; |
| import org.apache.commons.lang.math.LongRange; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.hadoop.security.UserGroupInformation; |
| import org.apache.hadoop.util.StringUtils; |
| import org.apache.hadoop.yarn.api.ApplicationBaseProtocol; |
| import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest; |
| import org.apache.hadoop.yarn.api.records.ApplicationReport; |
| import org.apache.hadoop.yarn.api.records.YarnApplicationState; |
| import org.apache.hadoop.yarn.exceptions.YarnException; |
| import org.apache.hadoop.yarn.server.webapp.dao.AppInfo; |
| import org.apache.hadoop.yarn.webapp.BadRequestException; |
| import org.apache.hadoop.yarn.webapp.hamlet.Hamlet; |
| import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE; |
| import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TBODY; |
| import org.apache.hadoop.yarn.webapp.view.HtmlBlock; |
| |
| import com.google.inject.Inject; |
| |
| public class AppsBlock extends HtmlBlock { |
| |
| private static final Log LOG = LogFactory.getLog(AppsBlock.class); |
| protected ApplicationBaseProtocol appBaseProt; |
| protected EnumSet<YarnApplicationState> reqAppStates; |
| protected UserGroupInformation callerUGI; |
| protected Collection<ApplicationReport> appReports; |
| |
| @Inject |
| protected AppsBlock(ApplicationBaseProtocol appBaseProt, ViewContext ctx) { |
| super(ctx); |
| this.appBaseProt = appBaseProt; |
| } |
| |
| protected void fetchData() throws YarnException, IOException, |
| InterruptedException { |
| reqAppStates = EnumSet.noneOf(YarnApplicationState.class); |
| String reqStateString = $(APP_STATE); |
| if (reqStateString != null && !reqStateString.isEmpty()) { |
| String[] appStateStrings = reqStateString.split(","); |
| for (String stateString : appStateStrings) { |
| reqAppStates.add(YarnApplicationState.valueOf(stateString.trim())); |
| } |
| } |
| callerUGI = getCallerUGI(); |
| final GetApplicationsRequest request = |
| GetApplicationsRequest.newInstance(reqAppStates); |
| String appsNumStr = $(APPS_NUM); |
| if (appsNumStr != null && !appsNumStr.isEmpty()) { |
| long appsNum = Long.parseLong(appsNumStr); |
| request.setLimit(appsNum); |
| } |
| |
| String appStartedTimeBegainStr = $(APP_START_TIME_BEGIN); |
| long appStartedTimeBegain = 0; |
| if (appStartedTimeBegainStr != null && !appStartedTimeBegainStr.isEmpty()) { |
| appStartedTimeBegain = Long.parseLong(appStartedTimeBegainStr); |
| if (appStartedTimeBegain < 0) { |
| throw new BadRequestException( |
| "app.started-time.begin must be greater than 0"); |
| } |
| } |
| String appStartedTimeEndStr = $(APP_START_TIME_END); |
| long appStartedTimeEnd = Long.MAX_VALUE; |
| if (appStartedTimeEndStr != null && !appStartedTimeEndStr.isEmpty()) { |
| appStartedTimeEnd = Long.parseLong(appStartedTimeEndStr); |
| if (appStartedTimeEnd < 0) { |
| throw new BadRequestException( |
| "app.started-time.end must be greater than 0"); |
| } |
| } |
| if (appStartedTimeBegain > appStartedTimeEnd) { |
| throw new BadRequestException( |
| "app.started-time.end must be greater than app.started-time.begin"); |
| } |
| request.setStartRange( |
| new LongRange(appStartedTimeBegain, appStartedTimeEnd)); |
| |
| if (callerUGI == null) { |
| appReports = appBaseProt.getApplications(request).getApplicationList(); |
| } else { |
| appReports = |
| callerUGI |
| .doAs(new PrivilegedExceptionAction<Collection<ApplicationReport>>() { |
| @Override |
| public Collection<ApplicationReport> run() throws Exception { |
| return appBaseProt.getApplications(request) |
| .getApplicationList(); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void render(Block html) { |
| setTitle("Applications"); |
| |
| try { |
| fetchData(); |
| } |
| catch( Exception e) { |
| String message = "Failed to read the applications."; |
| LOG.error(message, e); |
| html.p()._(message)._(); |
| return; |
| } |
| renderData(html); |
| } |
| |
| protected void renderData(Block html) { |
| TBODY<TABLE<Hamlet>> tbody = |
| html.table("#apps").thead().tr().th(".id", "ID").th(".user", "User") |
| .th(".name", "Name").th(".type", "Application Type") |
| .th(".queue", "Queue").th(".priority", "Application Priority") |
| .th(".starttime", "StartTime").th(".finishtime", "FinishTime") |
| .th(".state", "State").th(".finalstatus", "FinalStatus") |
| .th(".progress", "Progress").th(".ui", "Tracking UI")._()._().tbody(); |
| |
| StringBuilder appsTableData = new StringBuilder("[\n"); |
| for (ApplicationReport appReport : appReports) { |
| // TODO: remove the following condition. It is still here because |
| // the history side implementation of ApplicationBaseProtocol |
| // hasn't filtering capability (YARN-1819). |
| if (!reqAppStates.isEmpty() |
| && !reqAppStates.contains(appReport.getYarnApplicationState())) { |
| continue; |
| } |
| AppInfo app = new AppInfo(appReport); |
| String percent = StringUtils.format("%.1f", app.getProgress()); |
| appsTableData |
| .append("[\"<a href='") |
| .append(url("app", app.getAppId())) |
| .append("'>") |
| .append(app.getAppId()) |
| .append("</a>\",\"") |
| .append( |
| StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app |
| .getUser()))) |
| .append("\",\"") |
| .append( |
| StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app |
| .getName()))) |
| .append("\",\"") |
| .append( |
| StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app |
| .getType()))) |
| .append("\",\"") |
| .append( |
| StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(app |
| .getQueue()))).append("\",\"").append(String |
| .valueOf(app.getPriority())) |
| .append("\",\"").append(app.getStartedTime()) |
| .append("\",\"").append(app.getFinishedTime()) |
| .append("\",\"") |
| .append(app.getAppState() == null ? UNAVAILABLE : app.getAppState()) |
| .append("\",\"") |
| .append(app.getFinalAppStatus()) |
| .append("\",\"") |
| // Progress bar |
| .append("<br title='").append(percent).append("'> <div class='") |
| .append(C_PROGRESSBAR).append("' title='").append(join(percent, '%')) |
| .append("'> ").append("<div class='").append(C_PROGRESSBAR_VALUE) |
| .append("' style='").append(join("width:", percent, '%')) |
| .append("'> </div> </div>").append("\",\"<a "); |
| |
| String trackingURL = |
| app.getTrackingUrl() == null |
| || app.getTrackingUrl().equals(UNAVAILABLE) ? null : app |
| .getTrackingUrl(); |
| |
| String trackingUI = |
| app.getTrackingUrl() == null || app.getTrackingUrl().equals(UNAVAILABLE) |
| ? "Unassigned" |
| : app.getAppState() == YarnApplicationState.FINISHED |
| || app.getAppState() == YarnApplicationState.FAILED |
| || app.getAppState() == YarnApplicationState.KILLED |
| ? "History" : "ApplicationMaster"; |
| appsTableData.append(trackingURL == null ? "#" : "href='" + trackingURL) |
| .append("'>").append(trackingUI).append("</a>\"],\n"); |
| |
| } |
| if (appsTableData.charAt(appsTableData.length() - 2) == ',') { |
| appsTableData.delete(appsTableData.length() - 2, |
| appsTableData.length() - 1); |
| } |
| appsTableData.append("]"); |
| html.script().$type("text/javascript") |
| ._("var appsTableData=" + appsTableData)._(); |
| |
| tbody._()._(); |
| } |
| } |