jobdetails.jsp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <%@ page
  2. contentType="text/html; charset=UTF-8"
  3. import="javax.servlet.*"
  4. import="javax.servlet.http.*"
  5. import="java.io.*"
  6. import="java.text.*"
  7. import="java.util.*"
  8. import="java.text.DecimalFormat"
  9. import="org.apache.hadoop.http.HtmlQuoting"
  10. import="org.apache.hadoop.mapred.*"
  11. import="org.apache.hadoop.mapred.JSPUtil.JobWithViewAccessCheck"
  12. import="org.apache.hadoop.mapreduce.TaskType"
  13. import="org.apache.hadoop.util.*"
  14. import="org.apache.hadoop.mapreduce.JobACL"
  15. import="org.apache.hadoop.security.UserGroupInformation"
  16. import="java.security.PrivilegedExceptionAction"
  17. import="org.apache.hadoop.security.AccessControlException"
  18. import="org.apache.hadoop.security.authorize.AccessControlList"
  19. %>
  20. <%! private static final long serialVersionUID = 1L;
  21. %>
  22. <%
  23. final JobTracker tracker = (JobTracker) application.getAttribute(
  24. "job.tracker");
  25. String trackerName =
  26. StringUtils.simpleHostname(tracker.getJobTrackerMachine());
  27. %>
  28. <%!
  29. private void printTaskSummary(JspWriter out,
  30. String jobId,
  31. String kind,
  32. double completePercent,
  33. TaskInProgress[] tasks
  34. ) throws IOException {
  35. int totalTasks = tasks.length;
  36. int runningTasks = 0;
  37. int finishedTasks = 0;
  38. int killedTasks = 0;
  39. int failedTaskAttempts = 0;
  40. int killedTaskAttempts = 0;
  41. for(int i=0; i < totalTasks; ++i) {
  42. TaskInProgress task = tasks[i];
  43. if (task.isComplete()) {
  44. finishedTasks += 1;
  45. } else if (task.isRunning()) {
  46. runningTasks += 1;
  47. } else if (task.wasKilled()) {
  48. killedTasks += 1;
  49. }
  50. failedTaskAttempts += task.numTaskFailures();
  51. killedTaskAttempts += task.numKilledTasks();
  52. }
  53. int pendingTasks = totalTasks - runningTasks - killedTasks - finishedTasks;
  54. out.print("<tr><th><a href=\"jobtasks.jsp?jobid=" + jobId +
  55. "&type="+ kind + "&pagenum=1\">" + kind +
  56. "</a></th><td align=\"right\">" +
  57. StringUtils.formatPercent(completePercent, 2) +
  58. ServletUtil.percentageGraph((int)(completePercent * 100), 80) +
  59. "</td><td align=\"right\">" +
  60. totalTasks +
  61. "</td><td align=\"right\">" +
  62. ((pendingTasks > 0)
  63. ? "<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  64. "&pagenum=1" + "&state=pending\">" + pendingTasks + "</a>"
  65. : "0") +
  66. "</td><td align=\"right\">" +
  67. ((runningTasks > 0)
  68. ? "<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  69. "&pagenum=1" + "&state=running\">" + runningTasks + "</a>"
  70. : "0") +
  71. "</td><td align=\"right\">" +
  72. ((finishedTasks > 0)
  73. ?"<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  74. "&pagenum=1" + "&state=completed\">" + finishedTasks + "</a>"
  75. : "0") +
  76. "</td><td align=\"right\">" +
  77. ((killedTasks > 0)
  78. ?"<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  79. "&pagenum=1" + "&state=killed\">" + killedTasks + "</a>"
  80. : "0") +
  81. "</td><td align=\"right\">" +
  82. ((failedTaskAttempts > 0) ?
  83. ("<a href=\"jobfailures.jsp?jobid=" + jobId +
  84. "&kind=" + kind + "&cause=failed\">" + failedTaskAttempts +
  85. "</a>") :
  86. "0"
  87. ) +
  88. " / " +
  89. ((killedTaskAttempts > 0) ?
  90. ("<a href=\"jobfailures.jsp?jobid=" + jobId +
  91. "&kind=" + kind + "&cause=killed\">" + killedTaskAttempts +
  92. "</a>") :
  93. "0"
  94. ) +
  95. "</td></tr>\n");
  96. }
  97. private void printJobLevelTaskSummary(JspWriter out,
  98. String jobId,
  99. String kind,
  100. TaskInProgress[] tasks
  101. ) throws IOException {
  102. int totalTasks = tasks.length;
  103. int runningTasks = 0;
  104. int finishedTasks = 0;
  105. int killedTasks = 0;
  106. for(int i=0; i < totalTasks; ++i) {
  107. TaskInProgress task = tasks[i];
  108. if (task.isComplete()) {
  109. finishedTasks += 1;
  110. } else if (task.isRunning()) {
  111. runningTasks += 1;
  112. } else if (task.isFailed()) {
  113. killedTasks += 1;
  114. }
  115. }
  116. int pendingTasks = totalTasks - runningTasks - killedTasks - finishedTasks;
  117. out.print(((runningTasks > 0)
  118. ? "<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  119. "&pagenum=1" + "&state=running\">" + " Running" +
  120. "</a>"
  121. : ((pendingTasks > 0) ? " Pending" :
  122. ((finishedTasks > 0)
  123. ?"<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  124. "&pagenum=1" + "&state=completed\">" + " Successful"
  125. + "</a>"
  126. : ((killedTasks > 0)
  127. ?"<a href=\"jobtasks.jsp?jobid=" + jobId + "&type="+ kind +
  128. "&pagenum=1" + "&state=killed\">" + " Failed"
  129. + "</a>" : "None")))));
  130. }
  131. private void printConfirm(JspWriter out, String jobId) throws IOException{
  132. String url = "jobdetails.jsp?jobid=" + jobId;
  133. out.print("<html><head><META http-equiv=\"refresh\" content=\"15;URL="
  134. + url+"\"></head>"
  135. + "<body><h3> Are you sure you want to kill " + jobId
  136. + " ?<h3><br><table border=\"0\"><tr><td width=\"100\">"
  137. + "<form action=\"" + url + "\" method=\"post\">"
  138. + "<input type=\"hidden\" name=\"action\" value=\"kill\" />"
  139. + "<input type=\"submit\" name=\"kill\" value=\"Kill\" />"
  140. + "</form>"
  141. + "</td><td width=\"100\"><form method=\"post\" action=\"" + url
  142. + "\"><input type=\"submit\" value=\"Cancel\" name=\"Cancel\""
  143. + "/></form></td></tr></table></body></html>");
  144. }
  145. %>
  146. <%
  147. String jobId = request.getParameter("jobid");
  148. String refreshParam = request.getParameter("refresh");
  149. if (jobId == null) {
  150. out.println("<h2>Missing 'jobid'!</h2>");
  151. return;
  152. }
  153. int refresh = 60; // refresh every 60 seconds by default
  154. if (refreshParam != null) {
  155. try {
  156. refresh = Integer.parseInt(refreshParam);
  157. }
  158. catch (NumberFormatException ignored) {
  159. }
  160. }
  161. final JobID jobIdObj = JobID.forName(jobId);
  162. JobWithViewAccessCheck myJob = JSPUtil.checkAccessAndGetJob(tracker, jobIdObj,
  163. request, response);
  164. if (!myJob.isViewJobAllowed()) {
  165. return; // user is not authorized to view this job
  166. }
  167. JobInProgress job = myJob.getJob();
  168. final String newPriority = request.getParameter("prio");
  169. String user = request.getRemoteUser();
  170. UserGroupInformation ugi = null;
  171. if (user != null) {
  172. ugi = UserGroupInformation.createRemoteUser(user);
  173. }
  174. String action = request.getParameter("action");
  175. if(JSPUtil.privateActionsAllowed(tracker.conf) &&
  176. "changeprio".equalsIgnoreCase(action)
  177. && request.getMethod().equalsIgnoreCase("POST")) {
  178. if (ugi != null) {
  179. try {
  180. ugi.doAs(new PrivilegedExceptionAction<Void>() {
  181. public Void run() throws IOException{
  182. // checks job modify permission
  183. tracker.setJobPriority(jobIdObj,
  184. JobPriority.valueOf(newPriority));
  185. return null;
  186. }
  187. });
  188. } catch(AccessControlException e) {
  189. String errMsg = "User " + user + " failed to modify priority of " +
  190. jobIdObj + "!<br><br>" + e.getMessage() +
  191. "<hr><a href=\"jobdetails.jsp?jobid=" + jobId +
  192. "\">Go back to Job</a><br>";
  193. JSPUtil.setErrorAndForward(errMsg, request, response);
  194. return;
  195. }
  196. }
  197. else {// no authorization needed
  198. tracker.setJobPriority(jobIdObj,
  199. JobPriority.valueOf(newPriority));;
  200. }
  201. }
  202. if(JSPUtil.privateActionsAllowed(tracker.conf)) {
  203. action = request.getParameter("action");
  204. if(action!=null && action.equalsIgnoreCase("confirm")) {
  205. printConfirm(out, jobId);
  206. return;
  207. }
  208. else if(action != null && action.equalsIgnoreCase("kill") &&
  209. request.getMethod().equalsIgnoreCase("POST")) {
  210. if (ugi != null) {
  211. try {
  212. ugi.doAs(new PrivilegedExceptionAction<Void>() {
  213. public Void run() throws IOException{
  214. // checks job modify permission
  215. tracker.killJob(jobIdObj);// checks job modify permission
  216. return null;
  217. }
  218. });
  219. } catch(AccessControlException e) {
  220. String errMsg = "User " + user + " failed to kill " + jobIdObj +
  221. "!<br><br>" + e.getMessage() +
  222. "<hr><a href=\"jobdetails.jsp?jobid=" + jobId +
  223. "\">Go back to Job</a><br>";
  224. JSPUtil.setErrorAndForward(errMsg, request, response);
  225. return;
  226. }
  227. }
  228. else {// no authorization needed
  229. tracker.killJob(jobIdObj);
  230. }
  231. }
  232. }
  233. %>
  234. <%@page import="org.apache.hadoop.mapred.TaskGraphServlet"%>
  235. <html>
  236. <head>
  237. <%
  238. if (refresh != 0) {
  239. %>
  240. <meta http-equiv="refresh" content="<%=refresh%>">
  241. <%
  242. }
  243. %>
  244. <title>Hadoop <%=jobId%> on <%=trackerName%></title>
  245. <link rel="stylesheet" type="text/css" href="/static/hadoop.css">
  246. </head>
  247. <body>
  248. <h1>Hadoop <%=jobId%> on <a href="jobtracker.jsp"><%=trackerName%></a></h1>
  249. <%
  250. if (job == null) {
  251. String historyFile = JobHistory.getHistoryFilePath(jobIdObj);
  252. if (historyFile == null) {
  253. out.println("<h2>Job " + jobId + " not known!</h2>");
  254. return;
  255. }
  256. String historyUrl = JobHistoryServer.getHistoryUrlPrefix(tracker.conf) +
  257. "/jobdetailshistory.jsp?logFile=" +
  258. JobHistory.JobInfo.encodeJobHistoryFilePath(historyFile);
  259. response.sendRedirect(response.encodeRedirectURL(historyUrl));
  260. return;
  261. }
  262. JobProfile profile = job.getProfile();
  263. JobStatus status = job.getStatus();
  264. int runState = status.getRunState();
  265. int flakyTaskTrackers = job.getNoOfBlackListedTrackers();
  266. out.print("<b>User:</b> " +
  267. HtmlQuoting.quoteHtmlChars(profile.getUser()) + "<br>\n");
  268. out.print("<b>Job Name:</b> " +
  269. HtmlQuoting.quoteHtmlChars(profile.getJobName()) + "<br>\n");
  270. out.print("<b>Job File:</b> <a href=\"jobconf.jsp?jobid=" + jobId + "\">" +
  271. profile.getJobFile() + "</a><br>\n");
  272. out.print("<b>Submit Host:</b> " +
  273. HtmlQuoting.quoteHtmlChars(job.getJobSubmitHostName()) + "<br>\n");
  274. out.print("<b>Submit Host Address:</b> " +
  275. HtmlQuoting.quoteHtmlChars(job.getJobSubmitHostAddress()) + "<br>\n");
  276. Map<JobACL, AccessControlList> jobAcls = status.getJobACLs();
  277. JSPUtil.printJobACLs(tracker, jobAcls, out);
  278. out.print("<b>Job Setup:</b>");
  279. printJobLevelTaskSummary(out, jobId, "setup",
  280. job.getTasks(TaskType.JOB_SETUP));
  281. out.print("<br>\n");
  282. if (runState == JobStatus.RUNNING) {
  283. out.print("<b>Status:</b> Running<br>\n");
  284. out.print("<b>Started at:</b> " + new Date(job.getStartTime()) + "<br>\n");
  285. out.print("<b>Running for:</b> " + StringUtils.formatTimeDiff(
  286. System.currentTimeMillis(), job.getStartTime()) + "<br>\n");
  287. } else {
  288. if (runState == JobStatus.SUCCEEDED) {
  289. out.print("<b>Status:</b> Succeeded<br>\n");
  290. out.print("<b>Started at:</b> " + new Date(job.getStartTime()) + "<br>\n");
  291. out.print("<b>Finished at:</b> " + new Date(job.getFinishTime()) +
  292. "<br>\n");
  293. out.print("<b>Finished in:</b> " + StringUtils.formatTimeDiff(
  294. job.getFinishTime(), job.getStartTime()) + "<br>\n");
  295. } else if (runState == JobStatus.FAILED) {
  296. out.print("<b>Status:</b> Failed<br>\n");
  297. out.print("<b>Started at:</b> " + new Date(job.getStartTime()) + "<br>\n");
  298. out.print("<b>Failed at:</b> " + new Date(job.getFinishTime()) +
  299. "<br>\n");
  300. out.print("<b>Failed in:</b> " + StringUtils.formatTimeDiff(
  301. job.getFinishTime(), job.getStartTime()) + "<br>\n");
  302. } else if (runState == JobStatus.KILLED) {
  303. out.print("<b>Status:</b> Killed<br>\n");
  304. out.print("<b>Started at:</b> " + new Date(job.getStartTime()) + "<br>\n");
  305. out.print("<b>Killed at:</b> " + new Date(job.getFinishTime()) +
  306. "<br>\n");
  307. out.print("<b>Killed in:</b> " + StringUtils.formatTimeDiff(
  308. job.getFinishTime(), job.getStartTime()) + "<br>\n");
  309. }
  310. }
  311. out.print("<b>Job Cleanup:</b>");
  312. printJobLevelTaskSummary(out, jobId, "cleanup",
  313. job.getTasks(TaskType.JOB_CLEANUP));
  314. out.print("<br>\n");
  315. if (flakyTaskTrackers > 0) {
  316. out.print("<b>Black-listed TaskTrackers:</b> " +
  317. "<a href=\"jobblacklistedtrackers.jsp?jobid=" + jobId + "\">" +
  318. flakyTaskTrackers + "</a><br>\n");
  319. }
  320. if (job.getSchedulingInfo() != null) {
  321. out.print("<b>Job Scheduling information: </b>" +
  322. job.getSchedulingInfo().toString() +"\n");
  323. }
  324. out.print("<hr>\n");
  325. out.print("<table border=2 cellpadding=\"5\" cellspacing=\"2\">");
  326. out.print("<tr><th>Kind</th><th>% Complete</th><th>Num Tasks</th>" +
  327. "<th>Pending</th><th>Running</th><th>Complete</th>" +
  328. "<th>Killed</th>" +
  329. "<th><a href=\"jobfailures.jsp?jobid=" + jobId +
  330. "\">Failed/Killed<br>Task Attempts</a></th></tr>\n");
  331. printTaskSummary(out, jobId, "map", status.mapProgress(),
  332. job.getTasks(TaskType.MAP));
  333. printTaskSummary(out, jobId, "reduce", status.reduceProgress(),
  334. job.getTasks(TaskType.REDUCE));
  335. out.print("</table>\n");
  336. %>
  337. <p/>
  338. <table border=2 cellpadding="5" cellspacing="2">
  339. <tr>
  340. <th><br/></th>
  341. <th>Counter</th>
  342. <th>Map</th>
  343. <th>Reduce</th>
  344. <th>Total</th>
  345. </tr>
  346. <%
  347. Counters mapCounters = job.getMapCounters();
  348. Counters reduceCounters = job.getReduceCounters();
  349. Counters totalCounters = job.getCounters();
  350. for (String groupName : totalCounters.getGroupNames()) {
  351. Counters.Group totalGroup = totalCounters.getGroup(groupName);
  352. Counters.Group mapGroup = mapCounters.getGroup(groupName);
  353. Counters.Group reduceGroup = reduceCounters.getGroup(groupName);
  354. Format decimal = new DecimalFormat();
  355. boolean isFirst = true;
  356. for (Counters.Counter counter : totalGroup) {
  357. String name = counter.getDisplayName();
  358. String mapValue = decimal.format(mapGroup.getCounter(name));
  359. String reduceValue = decimal.format(reduceGroup.getCounter(name));
  360. String totalValue = decimal.format(counter.getCounter());
  361. %>
  362. <tr>
  363. <%
  364. if (isFirst) {
  365. isFirst = false;
  366. %>
  367. <td rowspan="<%=totalGroup.size()%>">
  368. <%=HtmlQuoting.quoteHtmlChars(totalGroup.getDisplayName())%></td>
  369. <%
  370. }
  371. %>
  372. <td><%=HtmlQuoting.quoteHtmlChars(name)%></td>
  373. <td align="right"><%=mapValue%></td>
  374. <td align="right"><%=reduceValue%></td>
  375. <td align="right"><%=totalValue%></td>
  376. </tr>
  377. <%
  378. }
  379. }
  380. %>
  381. </table>
  382. <hr>Map Completion Graph -
  383. <%
  384. if("off".equals(request.getParameter("map.graph"))) {
  385. session.setAttribute("map.graph", "off");
  386. } else if("on".equals(request.getParameter("map.graph"))){
  387. session.setAttribute("map.graph", "on");
  388. }
  389. if("off".equals(request.getParameter("reduce.graph"))) {
  390. session.setAttribute("reduce.graph", "off");
  391. } else if("on".equals(request.getParameter("reduce.graph"))){
  392. session.setAttribute("reduce.graph", "on");
  393. }
  394. if("off".equals(session.getAttribute("map.graph"))) { %>
  395. <a href="/jobdetails.jsp?jobid=<%=jobId%>&refresh=<%=refresh%>&map.graph=on" > open </a>
  396. <%} else { %>
  397. <a href="/jobdetails.jsp?jobid=<%=jobId%>&refresh=<%=refresh%>&map.graph=off" > close </a>
  398. <br><embed src="/taskgraph?type=map&jobid=<%=jobId%>"
  399. width="<%=TaskGraphServlet.width + 2 * TaskGraphServlet.xmargin%>"
  400. height="<%=TaskGraphServlet.height + 3 * TaskGraphServlet.ymargin%>"
  401. style="width:100%" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" />
  402. <%}%>
  403. <%if(job.getTasks(TaskType.REDUCE).length > 0) { %>
  404. <hr>Reduce Completion Graph -
  405. <%if("off".equals(session.getAttribute("reduce.graph"))) { %>
  406. <a href="/jobdetails.jsp?jobid=<%=jobId%>&refresh=<%=refresh%>&reduce.graph=on" > open </a>
  407. <%} else { %>
  408. <a href="/jobdetails.jsp?jobid=<%=jobId%>&refresh=<%=refresh%>&reduce.graph=off" > close </a>
  409. <br><embed src="/taskgraph?type=reduce&jobid=<%=jobId%>"
  410. width="<%=TaskGraphServlet.width + 2 * TaskGraphServlet.xmargin%>"
  411. height="<%=TaskGraphServlet.height + 3 * TaskGraphServlet.ymargin%>"
  412. style="width:100%" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" />
  413. <%} }%>
  414. <hr>
  415. <% if(JSPUtil.privateActionsAllowed(tracker.conf)) { %>
  416. <table border="0"> <tr> <td>
  417. Change priority from <%=job.getPriority()%> to:
  418. <form action="jobdetails.jsp" method="post">
  419. <input type="hidden" name="action" value="changeprio"/>
  420. <input type="hidden" name="jobid" value="<%=jobId%>"/>
  421. </td><td> <select name="prio">
  422. <%
  423. JobPriority jobPrio = job.getPriority();
  424. for (JobPriority prio : JobPriority.values()) {
  425. if(jobPrio != prio) {
  426. %> <option value=<%=prio%>><%=prio%></option> <%
  427. }
  428. }
  429. %>
  430. </select> </td><td><input type="submit" value="Submit"> </form></td></tr> </table>
  431. <% } %>
  432. <table border="0"> <tr>
  433. <% if(JSPUtil.privateActionsAllowed(tracker.conf)
  434. && runState == JobStatus.RUNNING) { %>
  435. <br/><a href="jobdetails.jsp?action=confirm&jobid=<%=jobId%>"> Kill this job </a>
  436. <% } %>
  437. <hr>
  438. <hr>
  439. <a href="jobtracker.jsp">Go back to JobTracker</a><br>
  440. <%
  441. out.println(ServletUtil.htmlFooter());
  442. %>