| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hadoop.yarn.server.resourcemanager.webapp; |
| |
| import static org.apache.hadoop.yarn.webapp.view.JQueryUI._EVEN; |
| import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP; |
| import static org.apache.hadoop.yarn.webapp.view.JQueryUI._ODD; |
| import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH; |
| |
| import java.io.IOException; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.apache.commons.text.StringEscapeUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationAttemptReportRequest; |
| import org.apache.hadoop.yarn.api.protocolrecords.GetContainersRequest; |
| import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport; |
| import org.apache.hadoop.yarn.api.records.ApplicationId; |
| import org.apache.hadoop.yarn.api.records.ContainerReport; |
| import org.apache.hadoop.yarn.api.records.Resource; |
| import org.apache.hadoop.yarn.api.records.ResourceRequest; |
| import org.apache.hadoop.yarn.api.records.YarnApplicationAttemptState; |
| import org.apache.hadoop.yarn.exceptions.YarnException; |
| import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; |
| import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; |
| import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt; |
| import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics; |
| import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler; |
| import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo; |
| import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceRequestInfo; |
| import org.apache.hadoop.yarn.server.webapp.AppAttemptBlock; |
| import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo; |
| import org.apache.hadoop.yarn.util.Times; |
| import org.apache.hadoop.yarn.util.resource.Resources; |
| import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet; |
| import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.DIV; |
| import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.TABLE; |
| import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.TBODY; |
| import org.apache.hadoop.yarn.webapp.util.WebAppUtils; |
| import org.apache.hadoop.yarn.webapp.view.InfoBlock; |
| |
| import com.google.inject.Inject; |
| |
| public class RMAppAttemptBlock extends AppAttemptBlock{ |
| |
| private final ResourceManager rm; |
| protected Configuration conf; |
| private final static String DIAGNOSTICS_SCRIPT_BODY = new StringBuilder() |
| .append("var refresh = false;") |
| .append("var haveGotAppDiagnostic = false;") |
| .append("function getArray(objOrArray) {") |
| .append(" if(Array.isArray(objOrArray)){") |
| .append(" return objOrArray;") |
| .append(" } else {") |
| .append(" return [objOrArray];") |
| .append(" }") |
| .append("}") |
| .append("function getTableDataFromObjectArray(objectArray, fields) {") |
| .append(" if (objectArray == undefined) {") |
| .append(" return [];") |
| .append(" }") |
| .append(" var data = [];") |
| .append(" $.each(objectArray, function(i, object) {") |
| .append(" var dataItem = [];") |
| .append(" for (var i=0; i<fields.length; i++) {") |
| .append(" dataItem.push(object[fields[i]] != undefined ? ") |
| .append("object[fields[i]] : '');") |
| .append(" }") |
| .append(" data.push(dataItem);") |
| .append(" });") |
| .append(" return data;") |
| .append("}") |
| .append("function sendRequest(requestURL, doneCallBackFunc,") |
| .append(" failCallBackFunc) {") |
| .append(" $.ajax({") |
| .append(" type: 'GET',") |
| .append(" url: requestURL,") |
| .append(" contentType: 'text/plain'") |
| .append(" }).done(doneCallBackFunc).fail(failCallBackFunc);") |
| .append("}") |
| .append("function parseQueryAppActResponse(responseObj) {") |
| .append(" var requestDiagnostics = [], dateTime, appDiagnostic;") |
| .append(" responseObj = responseObj['appActivities'];") |
| .append(" if(responseObj.hasOwnProperty('allocations')){") |
| .append(" var allocations = getArray(responseObj['allocations']);") |
| .append(" var allocation = allocations[0];") |
| .append(" dateTime = allocation['dateTime'];") |
| .append(" if(allocation.hasOwnProperty('diagnostic')){") |
| .append(" appDiagnostic = allocation['diagnostic'];") |
| .append(" }") |
| .append(" if(allocation.hasOwnProperty('children')){") |
| .append(" var requestAllocations = ") |
| .append(" getArray(allocation['children']);") |
| .append(" $.each(requestAllocations, function (i, requestAllocation) {") |
| .append(" if(requestAllocation.hasOwnProperty('children')){") |
| .append(" var allocationAttempts = ") |
| .append(" getArray(requestAllocation['children']);") |
| .append(" var diagnosticSummary = requestAllocation.hasOwnProperty(") |
| .append(" 'diagnostic')? requestAllocation['diagnostic']+'. ':'';") |
| .append(" $.each(allocationAttempts, function(i,allocationAttempt) {") |
| .append(" if (i > 0) {") |
| .append(" diagnosticSummary += ', ';") |
| .append(" }") |
| .append(" diagnosticSummary += allocationAttempt['count'] + ' ' +") |
| .append(" (allocationAttempt['count']=='1' ? 'node ' : 'nodes ')") |
| .append(" + allocationAttempt['allocationState'];") |
| .append(" if (allocationAttempt.hasOwnProperty('diagnostic')) {") |
| .append(" diagnosticSummary += ' with diagnostic:' + ") |
| .append(" allocationAttempt['diagnostic'];") |
| .append(" }") |
| .append(" });") |
| .append(" delete requestAllocation['children'];") |
| .append(" requestAllocation['diagnostic']=diagnosticSummary;") |
| .append(" }") |
| .append(" requestDiagnostics.push(requestAllocation);") |
| .append(" });") |
| .append(" }") |
| .append(" }") |
| .append(" return [requestDiagnostics, dateTime, appDiagnostic];") |
| .append("}") |
| .append("function handleQueryAppActDone(data){") |
| .append(" console.log('App activities:', data);") |
| .append(" var results = parseQueryAppActResponse(data);") |
| .append(" console.log('parsed results:', results);") |
| .append(" var requestDiagnostics = results[0];") |
| .append(" var dateTime = results[1];") |
| .append(" var appDiagnostic = results[2];") |
| .append(" haveGotAppDiagnostic = false;") |
| .append(" if (appDiagnostic != undefined) {") |
| .append(" haveGotAppDiagnostic = true;") |
| .append(" $('#appDiagnostic').html('App diagnostic: '") |
| .append(" + appDiagnostic);") |
| .append(" }") |
| .append(" $('#diagnosticsTableDiv').empty();") |
| .append(" if (requestDiagnostics.length > 0) {") |
| .append(" haveGotAppDiagnostic = true;") |
| .append(" tableData = getTableDataFromObjectArray(requestDiagnostics,") |
| .append(" ['requestPriority', 'allocationRequestId', 'allocationState',") |
| .append(" 'diagnostic']);") |
| .append(" $('#diagnosticsTableDiv').append('<table ") |
| .append(" id=\"diagnosticsTable\"></table>');") |
| .append(" $('#diagnosticsTable').dataTable( {") |
| .append(" 'aaData': tableData,") |
| .append(" 'aoColumns': [") |
| .append(" { 'sTitle': 'Priority' },") |
| .append(" { 'sTitle': 'AllocationRequestId' },") |
| .append(" { 'sTitle': 'AllocationState' },") |
| .append(" { 'sTitle': 'DiagnosticSummary' }") |
| .append(" ],") |
| .append(" bJQueryUI:true, sPaginationType: 'full_numbers',") |
| .append(" iDisplayLength:20, aLengthMenu:[20, 40, 60, 80, 100]") |
| .append(" });") |
| .append(" }") |
| .append(" if (haveGotAppDiagnostic) {") |
| .append(" $('#refreshDiagnosticsBtn').attr('disabled',false);") |
| .append(" $('#diagnosticsUpdateTime').html('Updated at ' + dateTime);") |
| .append(" } else {") |
| .append(" $('#diagnosticsUpdateTime').html('');") |
| .append(" if (refresh) {") |
| .append(" refreshSchedulerDiagnostics();") |
| .append(" }") |
| .append(" }") |
| .append("}") |
| .append("function handleRequestFailure(data){") |
| .append(" alert('Request app activities REST API failed.');") |
| .append(" console.log(data);") |
| .append("}") |
| .append("function handleRefreshAppActDone(data){") |
| .append(" refresh = true;") |
| .append(" setTimeout(function(){") |
| .append(" queryAppDiagnostics();") |
| .append(" }, 2000);") |
| .append("}") |
| .append("function refreshAppDiagnostics() {") |
| .append(" $('#refreshDiagnosticsBtn').attr('disabled',true);") |
| .append(" sendRequest(refreshAppActivitiesURL,handleRefreshAppActDone,") |
| .append(" handleRequestFailure);") |
| .append("}") |
| .append("function queryAppDiagnostics() {") |
| .append(" sendRequest(getAppActivitiesURL,handleQueryAppActDone,") |
| .append(" handleRequestFailure);") |
| .append("}") |
| .append("function parseHierarchicalQueue(node, nodeInfos,") |
| .append(" parentNodePath, partition) {") |
| .append(" var nodePath = parentNodePath + '/' + node['name'];") |
| .append(" if (node.hasOwnProperty('name')){") |
| .append(" if (node['diagnostic'] == undefined || node['diagnostic']") |
| .append(" .indexOf(ignoreActivityContent) == -1){") |
| .append(" var nodeInfo = {};") |
| .append(" nodeInfo['partition'] = partition;") |
| .append(" nodeInfo['path'] = nodePath;") |
| .append(" nodeInfo['allocationState'] = node['allocationState'];") |
| .append(" nodeInfo['diagnostic'] = ") |
| .append(" node['diagnostic'] == undefined ? '':node['diagnostic'];") |
| .append(" nodeInfos.push(nodeInfo);") |
| .append(" }") |
| .append(" }") |
| .append(" if (node.hasOwnProperty('children')){") |
| .append(" var children = getArray(node['children']);") |
| .append(" $.each(children, function (i, child) {") |
| .append(" parseHierarchicalQueue(child, nodeInfos, nodePath,") |
| .append(" partition);") |
| .append(" });") |
| .append(" }") |
| .append("}") |
| .append("function parseQueueDiagnostics(data) {") |
| .append(" var nodeInfos = [], dateTime;") |
| .append(" if(data.hasOwnProperty('dateTime')){") |
| .append(" dateTime = data['dateTime'];") |
| .append(" }") |
| .append(" if(data.hasOwnProperty('allocations')){") |
| .append(" var allocations = getArray(data['allocations']);") |
| .append(" $.each(allocations, function (i, allocation) {") |
| .append(" if (allocation.hasOwnProperty('root')) {") |
| .append(" var root = allocation['root'];") |
| .append(" var partition = allocation['partition'];") |
| .append(" parseHierarchicalQueue(root, nodeInfos, '', partition);") |
| .append(" }") |
| .append(" });") |
| .append(" }") |
| .append(" return [nodeInfos, dateTime];") |
| .append("}") |
| .append("function handleRefreshSchedulerActDone(data){") |
| .append(" console.log('handleRefreshSchedulerActDone', data);") |
| .append(" setTimeout(function(){") |
| .append(" querySchedulerDiagnostics();") |
| .append(" $('#refreshDiagnosticsBtn').attr('disabled',false);") |
| .append(" }, 100);") |
| .append("}") |
| .append("function handleQuerySchedulerActDone(data){") |
| .append(" console.log('Scheduler activities:', data);") |
| .append(" data = data['activities'];") |
| .append(" var results = parseQueueDiagnostics(data);") |
| .append(" var nodeInfos = results[0];") |
| .append(" var dateTime = results[1];") |
| .append(" $('#diagnosticsTableDiv').empty();") |
| .append(" if(dateTime != undefined){") |
| .append(" $('#diagnosticsUpdateTime').html('App diagnostics not found!") |
| .append(" Got useful scheduler activities updated at '+dateTime);") |
| .append(" tableData = getTableDataFromObjectArray(nodeInfos, ") |
| .append(" ['partition', 'path', 'allocationState', 'diagnostic']);") |
| .append(" $('#diagnosticsTableDiv').append('<table ") |
| .append(" id=\"diagnosticsTable\"></table>');") |
| .append(" $('#diagnosticsTable').dataTable({") |
| .append(" 'aaData': tableData,") |
| .append(" 'aoColumns': [") |
| .append(" { 'sTitle': 'Partition' },") |
| .append(" { 'sTitle': 'SchedulingNode' },") |
| .append(" { 'sTitle': 'AllocationState' },") |
| .append(" { 'sTitle': 'Diagnostic' }") |
| .append(" ],") |
| .append(" bJQueryUI:true, sPaginationType: 'full_numbers',") |
| .append(" iDisplayLength:20, aLengthMenu:[20, 40, 60, 80, 100]") |
| .append(" });") |
| .append(" } else if(data.hasOwnProperty('diagnostic')){") |
| .append(" $('#diagnosticsUpdateTime').html(data['diagnostic']);") |
| .append(" }") |
| .append(" $('#refreshDiagnosticsBtn').attr('disabled',false);") |
| .append("}") |
| .append("function refreshSchedulerDiagnostics() {") |
| .append(" $('#refreshDiagnosticsBtn').attr('disabled',true);") |
| .append(" sendRequest(schedulerActivitiesURL,") |
| .append(" handleRefreshSchedulerActDone,handleRequestFailure);") |
| .append("}") |
| .append("function querySchedulerDiagnostics() {") |
| .append(" sendRequest(schedulerActivitiesURL,") |
| .append(" handleQuerySchedulerActDone,handleRequestFailure);") |
| .append("}") |
| .append("queryAppDiagnostics();").toString(); |
| |
| @Inject |
| RMAppAttemptBlock(ViewContext ctx, ResourceManager rm, Configuration conf) { |
| super(null, ctx); |
| this.rm = rm; |
| this.conf = conf; |
| } |
| |
| private void createResourceRequestsTable(Block html) { |
| AppInfo app = |
| new AppInfo(rm, rm.getRMContext().getRMApps() |
| .get(this.appAttemptId.getApplicationId()), true, |
| WebAppUtils.getHttpSchemePrefix(conf)); |
| |
| List<ResourceRequestInfo> resourceRequests = app.getResourceRequests(); |
| if (resourceRequests == null || resourceRequests.isEmpty()) { |
| return; |
| } |
| |
| DIV<Hamlet> div = html.div(_INFO_WRAP); |
| // Requests Table |
| TBODY<TABLE<DIV<Hamlet>>> tbody = div |
| .h3("Total Outstanding Resource Requests: " |
| + getTotalResource(resourceRequests)) |
| .table("#resourceRequests").thead().tr().th(".priority", "Priority") |
| .th(".allocationRequestId", "AllocationRequestId") |
| .th(".resource", "ResourceName").th(".capacity", "Capability") |
| .th(".containers", "NumContainers") |
| .th(".relaxlocality", "RelaxLocality") |
| .th(".labelexpression", "NodeLabelExpression") |
| .th(".executiontype", "ExecutionType") |
| .th(".allocationTags", "AllocationTags") |
| .th(".placementConstraint", "PlacementConstraint").__().__().tbody(); |
| |
| StringBuilder resourceRequestTableData = new StringBuilder("[\n"); |
| for (ResourceRequestInfo resourceRequest : resourceRequests) { |
| if (resourceRequest.getNumContainers() == 0) { |
| continue; |
| } |
| resourceRequestTableData.append("[\"") |
| .append(String.valueOf(resourceRequest.getPriority())).append("\",\"") |
| .append(String.valueOf(resourceRequest.getAllocationRequestId())) |
| .append("\",\"") |
| .append(resourceRequest.getResourceName() == null ? "N/A" |
| : resourceRequest.getResourceName()) |
| .append("\",\"") |
| .append(StringEscapeUtils.escapeEcmaScript(StringEscapeUtils |
| .escapeHtml4(String.valueOf(resourceRequest.getCapability())))) |
| .append("\",\"") |
| .append(String.valueOf(resourceRequest.getNumContainers())) |
| .append("\",\"") |
| .append(String.valueOf(resourceRequest.getRelaxLocality())) |
| .append("\",\"") |
| .append(resourceRequest.getNodeLabelExpression() == null ? "N/A" |
| : resourceRequest.getNodeLabelExpression()) |
| .append("\",\"") |
| .append(resourceRequest.getExecutionTypeRequest() == null ? "N/A" |
| : resourceRequest.getExecutionTypeRequest().getExecutionType()) |
| .append("\",\"") |
| .append(resourceRequest.getAllocationTags() == null ? "N/A" : |
| StringUtils.join(resourceRequest.getAllocationTags(), ",")) |
| .append("\",\"") |
| .append(resourceRequest.getPlacementConstraint() == null ? "N/A" |
| : resourceRequest.getPlacementConstraint()) |
| .append("\"],\n"); |
| } |
| if (resourceRequestTableData |
| .charAt(resourceRequestTableData.length() - 2) == ',') { |
| resourceRequestTableData.delete(resourceRequestTableData.length() - 2, |
| resourceRequestTableData.length() - 1); |
| } |
| resourceRequestTableData.append("]"); |
| html.script().$type("text/javascript") |
| .__("var resourceRequestsTableData=" + resourceRequestTableData).__(); |
| tbody.__().__(); |
| |
| // create diagnostics table when CS is enabled |
| createDiagnosticsTable(html, div); |
| |
| div.__(); |
| } |
| |
| private Resource getTotalResource(List<ResourceRequestInfo> requests) { |
| Resource totalResource = Resource.newInstance(0, 0); |
| if (requests == null) { |
| return totalResource; |
| } |
| for (ResourceRequestInfo request : requests) { |
| if (request.getNumContainers() == 0) { |
| continue; |
| } |
| if (request.getResourceName() == null || request.getResourceName() |
| .equals(ResourceRequest.ANY)) { |
| Resources.addTo( |
| totalResource, |
| Resources.multiply(request.getCapability().getResource(), |
| request.getNumContainers())); |
| } |
| } |
| return totalResource; |
| } |
| |
| private void createContainerLocalityTable(Block html) { |
| RMAppAttemptMetrics attemptMetrics = null; |
| RMAppAttempt attempt = getRMAppAttempt(); |
| if (attempt != null) { |
| attemptMetrics = attempt.getRMAppAttemptMetrics(); |
| } |
| |
| if (attemptMetrics == null) { |
| return; |
| } |
| |
| DIV<Hamlet> div = html.div(_INFO_WRAP); |
| TABLE<DIV<Hamlet>> table = |
| div.h3( |
| "Total Allocated Containers: " |
| + attemptMetrics.getTotalAllocatedContainers()).h3("Each table cell" |
| + " represents the number of NodeLocal/RackLocal/OffSwitch containers" |
| + " satisfied by NodeLocal/RackLocal/OffSwitch resource requests.").table( |
| "#containerLocality"); |
| table. |
| tr(). |
| th(_TH, ""). |
| th(_TH, "Node Local Request"). |
| th(_TH, "Rack Local Request"). |
| th(_TH, "Off Switch Request"). |
| __(); |
| |
| String[] containersType = |
| { "Num Node Local Containers (satisfied by)", "Num Rack Local Containers (satisfied by)", |
| "Num Off Switch Containers (satisfied by)" }; |
| boolean odd = false; |
| for (int i = 0; i < attemptMetrics.getLocalityStatistics().length; i++) { |
| table.tr((odd = !odd) ? _ODD : _EVEN).td(containersType[i]) |
| .td(String.valueOf(attemptMetrics.getLocalityStatistics()[i][0])) |
| .td(i == 0 ? "" : String.valueOf(attemptMetrics.getLocalityStatistics()[i][1])) |
| .td(i <= 1 ? "" : String.valueOf(attemptMetrics.getLocalityStatistics()[i][2])).__(); |
| } |
| table.__(); |
| div.__(); |
| } |
| |
| private boolean isApplicationInFinalState(YarnApplicationAttemptState state) { |
| return state == YarnApplicationAttemptState.FINISHED |
| || state == YarnApplicationAttemptState.FAILED |
| || state == YarnApplicationAttemptState.KILLED; |
| } |
| |
| @Override |
| protected void createAttemptHeadRoomTable(Block html) { |
| RMAppAttempt attempt = getRMAppAttempt(); |
| if (attempt != null) { |
| if (!isApplicationInFinalState(YarnApplicationAttemptState |
| .valueOf(attempt.getAppAttemptState().toString()))) { |
| RMAppAttemptMetrics metrics = attempt.getRMAppAttemptMetrics(); |
| DIV<Hamlet> pdiv = html.__(InfoBlock.class).div(_INFO_WRAP); |
| info("Application Attempt Overview").clear(); |
| info("Application Attempt Metrics").__( |
| "Application Attempt Headroom : ", metrics == null ? "N/A" : |
| metrics.getApplicationAttemptHeadroom()); |
| pdiv.__(); |
| } |
| } |
| } |
| |
| private RMAppAttempt getRMAppAttempt() { |
| ApplicationId appId = this.appAttemptId.getApplicationId(); |
| RMAppAttempt attempt = null; |
| RMApp rmApp = rm.getRMContext().getRMApps().get(appId); |
| if (rmApp != null) { |
| attempt = rmApp.getAppAttempts().get(appAttemptId); |
| } |
| return attempt; |
| } |
| |
| protected void generateOverview(ApplicationAttemptReport appAttemptReport, |
| Collection<ContainerReport> containers, AppAttemptInfo appAttempt, |
| String node) { |
| |
| RMAppAttempt rmAppAttempt = getRMAppAttempt(); |
| // nodes which are blacklisted by the application |
| String appBlacklistedNodes = |
| getNodeString(rmAppAttempt.getBlacklistedNodes()); |
| // nodes which are blacklisted by the RM for AM launches |
| String rmBlackListedNodes = |
| getNodeString(rmAppAttempt.getAMBlacklistManager() |
| .getBlacklistUpdates().getBlacklistAdditions()); |
| |
| info("Application Attempt Overview") |
| .__( |
| "Application Attempt State:", |
| appAttempt.getAppAttemptState() == null ? UNAVAILABLE : appAttempt |
| .getAppAttemptState()) |
| .__("Started:", Times.format(appAttempt.getStartedTime())) |
| .__("Elapsed:", |
| org.apache.hadoop.util.StringUtils.formatTime(Times.elapsed( |
| appAttempt.getStartedTime(), appAttempt.getFinishedTime()))) |
| .__( |
| "AM Container:", |
| appAttempt.getAmContainerId() == null || containers == null |
| || !hasAMContainer(appAttemptReport.getAMContainerId(), containers) |
| ? null : root_url("container", appAttempt.getAmContainerId()), |
| appAttempt.getAmContainerId() == null ? "N/A" : |
| String.valueOf(appAttempt.getAmContainerId())) |
| .__("Node:", node) |
| .__( |
| "Tracking URL:", |
| appAttempt.getTrackingUrl() == null |
| || appAttempt.getTrackingUrl().equals(UNAVAILABLE) ? null |
| : root_url(appAttempt.getTrackingUrl()), |
| appAttempt.getTrackingUrl() == null |
| || appAttempt.getTrackingUrl().equals(UNAVAILABLE) |
| ? "Unassigned" |
| : appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FINISHED |
| || appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FAILED |
| || appAttempt.getAppAttemptState() == YarnApplicationAttemptState.KILLED |
| ? "History" : "ApplicationMaster") |
| .__( |
| "Diagnostics Info:", |
| appAttempt.getDiagnosticsInfo() == null ? "" : appAttempt |
| .getDiagnosticsInfo()) |
| .__("Nodes blacklisted by the application:", appBlacklistedNodes) |
| .__("Nodes blacklisted by the system:", rmBlackListedNodes); |
| } |
| |
| private String getNodeString(Collection<String> nodes) { |
| String concatinatedString = "-"; |
| if (null != nodes && !nodes.isEmpty()) { |
| concatinatedString = StringUtils.join(nodes, ", "); |
| } |
| return concatinatedString; |
| } |
| |
| @Override |
| protected void createTablesForAttemptMetrics(Block html) { |
| createContainerLocalityTable(html); |
| createResourceRequestsTable(html); |
| } |
| |
| @Override |
| protected List<ContainerReport> getContainers( |
| final GetContainersRequest request) throws YarnException, IOException { |
| return rm.getClientRMService().getContainers(request).getContainerList(); |
| } |
| |
| @Override |
| protected ApplicationAttemptReport getApplicationAttemptReport( |
| final GetApplicationAttemptReportRequest request) |
| throws YarnException, IOException { |
| return rm.getClientRMService().getApplicationAttemptReport(request) |
| .getApplicationAttemptReport(); |
| } |
| |
| private void createDiagnosticsTable(Block html, DIV<Hamlet> parentDiv) { |
| if (!(rm.getResourceScheduler() instanceof CapacityScheduler)) { |
| return; |
| } |
| String appActivitiesURL = |
| new StringBuilder().append(RMWSConsts.RM_WEB_SERVICE_PATH).append( |
| RMWSConsts.SCHEDULER_APP_ACTIVITIES.replace("{appid}", |
| this.appAttemptId.getApplicationId().toString())).append("?") |
| .toString(); |
| String refreshAppActivitiesURL = appActivitiesURL + "actions=refresh"; |
| String getAppActivitiesURL = appActivitiesURL |
| + "actions=get&groupBy=diagnostic&summarize=true"; |
| String refreshAndGetAppActivitiesURL = appActivitiesURL |
| + "actions=refresh&actions=get&groupBy=diagnostic&summarize=true"; |
| String schedulerActivitiesURL = |
| new StringBuilder().append(RMWSConsts.RM_WEB_SERVICE_PATH) |
| .append(RMWSConsts.SCHEDULER_ACTIVITIES).append("?") |
| .append(RMWSConsts.GROUP_BY).append("=diagnostic").toString(); |
| |
| DIV<DIV<Hamlet>> div = parentDiv.div(); |
| div.p().__("Diagnostics in cache ").__("(For more details refer to ") |
| .a(refreshAndGetAppActivitiesURL, "App Activities").__(" or ") |
| .a(schedulerActivitiesURL, "Scheduler Activities").__(")").__(); |
| div.button().$id("refreshDiagnosticsBtn") |
| .$style("border-style: solid; border-color: #000000; border-width: 1px;" |
| + " cursor: hand; cursor: pointer; border-radius: 4px") |
| .$onclick("refreshAppDiagnostics()").b("Refresh").__(); |
| div.p().$id("diagnosticsUpdateTime").__(); |
| div.p().$id("appDiagnostic").__(); |
| div.div("#diagnosticsTableDiv").__(); |
| |
| div.__(); |
| |
| StringBuilder script = new StringBuilder(); |
| script |
| .append("var refreshAppActivitiesURL = '") |
| .append(refreshAppActivitiesURL).append("';") |
| .append("var getAppActivitiesURL = '") |
| .append(getAppActivitiesURL).append("';") |
| .append("var schedulerActivitiesURL = '") |
| .append(schedulerActivitiesURL).append("';") |
| .append("var ignoreActivityContent = '") |
| .append("does not need more resource';") |
| .append(DIAGNOSTICS_SCRIPT_BODY); |
| |
| html.script().$type("text/javascript").__(script.toString()).__(); |
| } |
| } |