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 static org.apache.hadoop.yarn.webapp.view.JQueryUI._EVEN;
22 import static org.apache.hadoop.yarn.webapp.view.JQueryUI._INFO_WRAP;
23 import static org.apache.hadoop.yarn.webapp.view.JQueryUI._ODD;
24 import static org.apache.hadoop.yarn.webapp.view.JQueryUI._TH;
25 
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
29 import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport;
30 import org.apache.hadoop.yarn.api.records.ApplicationId;
31 import org.apache.hadoop.yarn.api.records.ContainerReport;
32 import org.apache.hadoop.yarn.api.records.Resource;
33 import org.apache.hadoop.yarn.api.records.ResourceRequest;
34 import org.apache.hadoop.yarn.api.records.YarnApplicationAttemptState;
35 import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
36 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
37 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttempt;
38 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.attempt.RMAppAttemptMetrics;
39 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.AbstractYarnScheduler;
40 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerApplicationAttempt;
41 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo;
42 import org.apache.hadoop.yarn.server.webapp.AppAttemptBlock;
43 import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo;
44 import org.apache.hadoop.yarn.util.resource.Resources;
45 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
46 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.DIV;
47 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE;
48 import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
49 import org.apache.hadoop.yarn.webapp.view.InfoBlock;
50 import com.google.inject.Inject;
51 import java.util.List;
52 
53 import java.util.Collection;
54 import java.util.Set;
55 
56 public class RMAppAttemptBlock extends AppAttemptBlock{
57 
58   private final ResourceManager rm;
59   protected Configuration conf;
60 
61   @Inject
RMAppAttemptBlock(ViewContext ctx, ResourceManager rm, Configuration conf)62   RMAppAttemptBlock(ViewContext ctx, ResourceManager rm, Configuration conf) {
63     super(rm.getClientRMService(), ctx);
64     this.rm = rm;
65     this.conf = conf;
66   }
67 
createResourceRequestsTable(Block html)68   private void createResourceRequestsTable(Block html) {
69     AppInfo app =
70         new AppInfo(rm, rm.getRMContext().getRMApps()
71           .get(this.appAttemptId.getApplicationId()), true,
72           WebAppUtils.getHttpSchemePrefix(conf));
73 
74     List<ResourceRequest> resourceRequests = app.getResourceRequests();
75     if (resourceRequests == null || resourceRequests.isEmpty()) {
76       return;
77     }
78 
79     DIV<Hamlet> div = html.div(_INFO_WRAP);
80     TABLE<DIV<Hamlet>> table =
81         div.h3("Total Outstanding Resource Requests: "
82           + getTotalResource(resourceRequests)).table(
83               "#ResourceRequests");
84 
85     table.tr().
86       th(_TH, "Priority").
87       th(_TH, "ResourceName").
88       th(_TH, "Capability").
89       th(_TH, "NumContainers").
90       th(_TH, "RelaxLocality").
91       th(_TH, "NodeLabelExpression").
92     _();
93 
94     boolean odd = false;
95     for (ResourceRequest request : resourceRequests) {
96       if (request.getNumContainers() == 0) {
97         continue;
98       }
99       table.tr((odd = !odd) ? _ODD : _EVEN)
100         .td(String.valueOf(request.getPriority()))
101         .td(request.getResourceName())
102         .td(String.valueOf(request.getCapability()))
103         .td(String.valueOf(request.getNumContainers()))
104         .td(String.valueOf(request.getRelaxLocality()))
105         .td(request.getNodeLabelExpression() == null ? "N/A" : request
106             .getNodeLabelExpression())._();
107     }
108     table._();
109     div._();
110   }
111 
getTotalResource(List<ResourceRequest> requests)112   private Resource getTotalResource(List<ResourceRequest> requests) {
113     Resource totalResource = Resource.newInstance(0, 0);
114     if (requests == null) {
115       return totalResource;
116     }
117     for (ResourceRequest request : requests) {
118       if (request.getNumContainers() == 0) {
119         continue;
120       }
121       if (request.getResourceName().equals(ResourceRequest.ANY)) {
122         Resources.addTo(
123           totalResource,
124           Resources.multiply(request.getCapability(),
125             request.getNumContainers()));
126       }
127     }
128     return totalResource;
129   }
130 
createContainerLocalityTable(Block html)131   private void createContainerLocalityTable(Block html) {
132     RMAppAttemptMetrics attemptMetrics = null;
133     RMAppAttempt attempt = getRMAppAttempt();
134     if (attempt != null) {
135       attemptMetrics = attempt.getRMAppAttemptMetrics();
136     }
137 
138     if (attemptMetrics == null) {
139       return;
140     }
141 
142     DIV<Hamlet> div = html.div(_INFO_WRAP);
143     TABLE<DIV<Hamlet>> table =
144         div.h3(
145           "Total Allocated Containers: "
146               + attemptMetrics.getTotalAllocatedContainers()).h3("Each table cell"
147             + " represents the number of NodeLocal/RackLocal/OffSwitch containers"
148             + " satisfied by NodeLocal/RackLocal/OffSwitch resource requests.").table(
149           "#containerLocality");
150     table.
151       tr().
152         th(_TH, "").
153         th(_TH, "Node Local Request").
154         th(_TH, "Rack Local Request").
155         th(_TH, "Off Switch Request").
156       _();
157 
158     String[] containersType =
159         { "Num Node Local Containers (satisfied by)", "Num Rack Local Containers (satisfied by)",
160             "Num Off Switch Containers (satisfied by)" };
161     boolean odd = false;
162     for (int i = 0; i < attemptMetrics.getLocalityStatistics().length; i++) {
163       table.tr((odd = !odd) ? _ODD : _EVEN).td(containersType[i])
164         .td(String.valueOf(attemptMetrics.getLocalityStatistics()[i][0]))
165         .td(i == 0 ? "" : String.valueOf(attemptMetrics.getLocalityStatistics()[i][1]))
166         .td(i <= 1 ? "" : String.valueOf(attemptMetrics.getLocalityStatistics()[i][2]))._();
167     }
168     table._();
169     div._();
170   }
171 
isApplicationInFinalState(YarnApplicationAttemptState state)172   private boolean isApplicationInFinalState(YarnApplicationAttemptState state) {
173     return state == YarnApplicationAttemptState.FINISHED
174         || state == YarnApplicationAttemptState.FAILED
175         || state == YarnApplicationAttemptState.KILLED;
176   }
177 
178   @Override
createAttemptHeadRoomTable(Block html)179   protected void createAttemptHeadRoomTable(Block html) {
180     RMAppAttempt attempt = getRMAppAttempt();
181     if (attempt != null) {
182       if (!isApplicationInFinalState(YarnApplicationAttemptState
183           .valueOf(attempt.getAppAttemptState().toString()))) {
184         RMAppAttemptMetrics metrics = attempt.getRMAppAttemptMetrics();
185         DIV<Hamlet> pdiv = html._(InfoBlock.class).div(_INFO_WRAP);
186         info("Application Attempt Overview").clear();
187         info("Application Attempt Metrics")._(
188           "Application Attempt Headroom : ", metrics == null ? "N/A" :
189             metrics.getApplicationAttemptHeadroom());
190         pdiv._();
191       }
192     }
193   }
194 
getRMAppAttempt()195   private RMAppAttempt getRMAppAttempt() {
196     ApplicationId appId = this.appAttemptId.getApplicationId();
197     RMAppAttempt attempt = null;
198     RMApp rmApp = rm.getRMContext().getRMApps().get(appId);
199     if (rmApp != null) {
200       attempt = rmApp.getAppAttempts().get(appAttemptId);
201     }
202     return attempt;
203   }
204 
205   @Override
createTablesForAttemptMetrics(Block html)206   protected void createTablesForAttemptMetrics(Block html) {
207     createContainerLocalityTable(html);
208     createResourceRequestsTable(html);
209   }
210 
generateOverview(ApplicationAttemptReport appAttemptReport, Collection<ContainerReport> containers, AppAttemptInfo appAttempt, String node)211   protected void generateOverview(ApplicationAttemptReport appAttemptReport,
212       Collection<ContainerReport> containers, AppAttemptInfo appAttempt,
213       String node) {
214 
215     String blacklistedNodes = "-";
216     Set<String> nodes =
217         getBlacklistedNodes(rm, getRMAppAttempt().getAppAttemptId());
218     if (nodes != null) {
219       if (!nodes.isEmpty()) {
220         blacklistedNodes = StringUtils.join(nodes, ", ");
221       }
222     }
223 
224     info("Application Attempt Overview")
225       ._(
226         "Application Attempt State:",
227         appAttempt.getAppAttemptState() == null ? UNAVAILABLE : appAttempt
228           .getAppAttemptState())
229       ._(
230         "AM Container:",
231         appAttempt.getAmContainerId() == null || containers == null
232             || !hasAMContainer(appAttemptReport.getAMContainerId(), containers)
233             ? null : root_url("container", appAttempt.getAmContainerId()),
234         String.valueOf(appAttempt.getAmContainerId()))
235       ._("Node:", node)
236       ._(
237         "Tracking URL:",
238         appAttempt.getTrackingUrl() == null
239             || appAttempt.getTrackingUrl().equals(UNAVAILABLE) ? null
240             : root_url(appAttempt.getTrackingUrl()),
241         appAttempt.getTrackingUrl() == null
242             || appAttempt.getTrackingUrl().equals(UNAVAILABLE)
243             ? "Unassigned"
244             : appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FINISHED
245                 || appAttempt.getAppAttemptState() == YarnApplicationAttemptState.FAILED
246                 || appAttempt.getAppAttemptState() == YarnApplicationAttemptState.KILLED
247                 ? "History" : "ApplicationMaster")
248       ._(
249         "Diagnostics Info:",
250         appAttempt.getDiagnosticsInfo() == null ? "" : appAttempt
251           .getDiagnosticsInfo())._("Blacklisted Nodes:", blacklistedNodes);
252   }
253 
getBlacklistedNodes(ResourceManager rm, ApplicationAttemptId appid)254   public static Set<String> getBlacklistedNodes(ResourceManager rm,
255       ApplicationAttemptId appid) {
256     if (rm.getResourceScheduler() instanceof AbstractYarnScheduler) {
257       AbstractYarnScheduler ayScheduler =
258           (AbstractYarnScheduler) rm.getResourceScheduler();
259       SchedulerApplicationAttempt attempt =
260           ayScheduler.getApplicationAttempt(appid);
261       if (attempt != null) {
262         return attempt.getBlacklistedNodes();
263       }
264     }
265     return null;
266   }
267 }
268