<%! /** * Licensed 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. */ %> <%@ page import="javax.servlet.*" import="javax.servlet.http.*" import="java.io.*" import="java.lang.String" import="java.util.*" import="org.apache.hadoop.http.HtmlQuoting" import="org.apache.hadoop.mapred.*" import="org.apache.hadoop.mapred.JSPUtil.JobWithViewAccessCheck" import="org.apache.hadoop.util.*" import="java.text.SimpleDateFormat" import="org.apache.hadoop.security.UserGroupInformation" import="java.security.PrivilegedExceptionAction" import="org.apache.hadoop.security.AccessControlException" import="org.codehaus.jackson.map.ObjectMapper" %> <%!static SimpleDateFormat dateFormat = new SimpleDateFormat( "d-MMM-yyyy HH:mm:ss"); %> <%! private static final long serialVersionUID = 1L; %> <%!private void printConfirm(JspWriter out, String attemptid, String action) throws IOException { String url = "taskdetails.jsp?attemptid=" + attemptid; out.print("" + "

Are you sure you want to kill/fail " + attemptid + " ?


" + "
" + "" + "" + "
" + "
"); } %> <%! public static class ErrorResponse { private final long errorCode; private final String errorDescription; // Constructor ErrorResponse(long ec, String ed) { errorCode = ec; errorDescription = ed; } // Getters public long getErrorCode() { return errorCode; } public String getErrorDescription() { return errorDescription; } } public static class TaskDetailsResponse { public static class TaskAttemptInfo { public static class TaskAttemptTrackerInfo { private final String name; private final String host; private final int httpPort; private final String url; private final String node; // Constructor TaskAttemptTrackerInfo(String trackerName, JobTracker jobTracker) { name = trackerName; TaskTrackerStatus trackerStatus = jobTracker.getTaskTrackerStatus(name); if (trackerStatus != null) { host = trackerStatus.getHost(); httpPort = trackerStatus.getHttpPort(); url = "http://" + host + ":" + httpPort; node = jobTracker.getNode(host).toString(); } else { host = null; httpPort = 0; url = null; node = null; } } // Getters public String getName() { return name; } public String getHost() { return host; } public int getHttpPort() { return httpPort; } public String getUrl() { return url; } public String getNode() { return node; } } public static class EventTimingInfo { private final String timestamp; private final long durationSecs; // Constructor EventTimingInfo(long eventOccurrenceTimeMSecs, long previousEventOccurrenceTimeMSecs) { timestamp = dateFormat.format(new Date(eventOccurrenceTimeMSecs)); durationSecs = (0 != previousEventOccurrenceTimeMSecs) ? /* Pass the difference through Math.abs() to take care of cases * where previousEventOccurrenceTimeMSecs is in the future (likely * used only as a hack, when an event is in-progress). */ (Math.abs(eventOccurrenceTimeMSecs - previousEventOccurrenceTimeMSecs)/1000) : 0; } // Getters public String getTimestamp() { return timestamp; } public long getDurationSecs() { return durationSecs; } } private final String attemptId; private final TaskAttemptTrackerInfo taskAttemptTrackerInfo; private final TaskAttemptTrackerInfo cleanupAttemptTrackerInfo; private final String status; private final float progressPercentage; private final EventTimingInfo startTimingInfo; private final EventTimingInfo finishTimingInfo; private final EventTimingInfo shuffleTimingInfo; private final EventTimingInfo sortTimingInfo; private final String taskAttemptLogUrl; private final String cleanupAttemptLogUrl; private String generateAttemptLogUrl(String trackerName, JobTracker jobTracker, boolean isCleanupAttempt) { String attemptLogUrl = null; TaskTrackerStatus trackerStatus = jobTracker.getTaskTrackerStatus(trackerName); if (trackerStatus != null) { attemptLogUrl = TaskLogServlet.getTaskLogUrl(trackerStatus.getHost(), String.valueOf(trackerStatus.getHttpPort()), attemptId); if (attemptLogUrl != null) { attemptLogUrl += "&all=true"; if (isCleanupAttempt) { attemptLogUrl += "&cleanup=true"; } } } return attemptLogUrl; } // Constructor TaskAttemptInfo(String ai, String ttn, String ctn, TaskStatus ts, JobTracker jt, boolean isCleanupOrSetup) { attemptId = ai; taskAttemptTrackerInfo = new TaskAttemptTrackerInfo(ttn, jt); cleanupAttemptTrackerInfo = (ctn != null) ? new TaskAttemptTrackerInfo(ctn, jt) : null; status = ts.getRunState().toString(); progressPercentage = ts.getProgress() * 100.0f; startTimingInfo = new EventTimingInfo (ts.getStartTime(), 0); finishTimingInfo = new EventTimingInfo (ts.getFinishTime(), ts.getStartTime()); if (!ts.getIsMap() && !isCleanupOrSetup) { shuffleTimingInfo = new EventTimingInfo (ts.getShuffleFinishTime(), ts.getStartTime()); sortTimingInfo = new EventTimingInfo (ts.getSortFinishTime(), ts.getShuffleFinishTime()); } else { shuffleTimingInfo = null; sortTimingInfo = null; } taskAttemptLogUrl = generateAttemptLogUrl(ttn, jt, false); cleanupAttemptLogUrl = (ctn != null) ? generateAttemptLogUrl(ctn, jt, true) : null; } // Getters public String getAttemptId() { return attemptId; } public TaskAttemptTrackerInfo getTaskAttemptTrackerInfo() { return taskAttemptTrackerInfo; } public TaskAttemptTrackerInfo getCleanupAttemptTrackerInfo() { return cleanupAttemptTrackerInfo; } public String getStatus() { return status; } public float getProgressPercentage() { return progressPercentage; } public EventTimingInfo getStartTimingInfo() { return startTimingInfo; } public EventTimingInfo getFinishTimingInfo() { return finishTimingInfo; } public EventTimingInfo getShuffleTimingInfo() { return shuffleTimingInfo; } public EventTimingInfo getSortTimingInfo() { return sortTimingInfo; } public String getTaskAttemptLogUrl() { return taskAttemptLogUrl; } public String getCleanupAttemptLogUrl() { return cleanupAttemptLogUrl; } } private final String jobId; private final String taskId; private final Collection taskAttemptsInfo; private final Collection inputSplitLocationsInfo; // Constructor TaskDetailsResponse(String ji, String ti) { jobId = ji; taskId = ti; taskAttemptsInfo = new ArrayList(); inputSplitLocationsInfo = new ArrayList(); } // To add one TaskAttemptInfo object at a time. void addTaskAttemptInfo(TaskAttemptInfo tai) { taskAttemptsInfo.add(tai); } // To add one Input Split Location at a time. void addInputSplitLocation(String isl) { inputSplitLocationsInfo.add(isl); } // Getters public String getJobId() { return jobId; } public String getTaskId() { return taskId; } public Collection getTaskAttemptsInfo() { return taskAttemptsInfo; } public Collection getInputSplitLocationsInfo() { return inputSplitLocationsInfo; } } %> <% String response_format = request.getParameter("format"); if (response_format != null) { /* Eventually, the HTML output should also be driven off of these *Response * objects. * * Someday. */ TaskDetailsResponse theTaskDetailsResponse = null; ErrorResponse theErrorResponse = null; JobTracker tracker = (JobTracker) application.getAttribute("job.tracker"); String attemptid = request.getParameter("attemptid"); String tipid = request.getParameter("tipid"); /* Make sure at least one of the 2 possible query parameters were specified. */ if ((attemptid != null) || (tipid != null)) { TaskAttemptID attemptidObj = TaskAttemptID.forName(attemptid); // Obtain tipid for attemptId, if attemptId is available. TaskID tipidObj = (attemptidObj == null) ? TaskID.forName(tipid) : attemptidObj.getTaskID(); if (tipidObj != null) { // Obtain jobid from tipid final JobID jobidObj = tipidObj.getJobID(); String jobid = jobidObj.toString(); JobWithViewAccessCheck myJob = JSPUtil.checkAccessAndGetJob(tracker, jobidObj, request, response); /* Proceed only if the user is authorized to view this job. */ if (myJob.isViewJobAllowed()) { JobInProgress job = myJob.getJob(); if (job != null) { TaskInProgress tip = job.getTaskInProgress(tipidObj); if (tip != null) { TaskStatus[] ts = tip.getTaskStatuses(); if ((ts != null) && (ts.length > 0)) { boolean isCleanupOrSetup = (tip.isJobCleanupTask() || tip.isJobSetupTask()); theTaskDetailsResponse = new TaskDetailsResponse(jobid, tipidObj.toString()); /* Generate Task Attempts. */ for (int i = 0; i < ts.length; i++) { TaskStatus status = ts[i]; TaskAttemptID taskAttemptId = status.getTaskID(); String taskTrackerName = status.getTaskTracker(); String cleanupTrackerName = null; if (tip.isCleanupAttempt(taskAttemptId)) { cleanupTrackerName = tip.machineWhereCleanupRan(taskAttemptId); } theTaskDetailsResponse.addTaskAttemptInfo( new TaskDetailsResponse.TaskAttemptInfo( taskAttemptId.toString(), taskTrackerName, cleanupTrackerName, status, tracker, isCleanupOrSetup ) ); } /* Generate Input Split Locations. */ if (ts[0].getIsMap() && !isCleanupOrSetup) { for (String splitLocation: StringUtils.split(tracker.getTip(tipidObj). getSplitNodes())) { theTaskDetailsResponse.addInputSplitLocation(splitLocation); } } } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); theErrorResponse = new ErrorResponse(4103, "TaskAttempts For " + tipidObj.toString() + " Not Found"); } } } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); theErrorResponse = new ErrorResponse(4102, "JobID " + jobid + " Not Found"); } } else { /* TODO XXX Try and factor out JSPUtil.setErrorAndForward() for re-use * (and to not make it blindly dispatch to job_authorization_error.jsp, * which is all HTML. */ /* TODO XXX Make this return JSON, not HTML. */ /* Nothing to do here, since JSPUtil.setErrorAndForward() has already been * called from inside JSPUtil.checkAccessAndGetJob(). */ } } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); theErrorResponse = new ErrorResponse(4101, ((attemptid == null) ? ("TipID " + tipid) : ("AttemptID " + attemptid)) + " Invalid"); } } else { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); theErrorResponse = new ErrorResponse(4100, "Missing TipID/AttemptID"); } /* ------------ Response generation begins here ------------ */ /* For now, "json" is the only supported format. * * As more formats are supported, this should become a cascading * if-elsif-else block. */ if ("json".equals(response_format)) { response.setContentType("application/json"); ObjectMapper responseObjectMapper = new ObjectMapper(); /* A lack of an error response implies we have a meaningful * application response? Why not! */ out.println(responseObjectMapper.writeValueAsString ((theErrorResponse == null) ? theTaskDetailsResponse : theErrorResponse)); } else { response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED); } } else { %> <% // Spit out HTML only in the absence of the "format" query parameter. response.setContentType("text/html; charset=UTF-8"); final JobTracker tracker = (JobTracker) application.getAttribute("job.tracker"); String attemptid = request.getParameter("attemptid"); final TaskAttemptID attemptidObj = TaskAttemptID.forName(attemptid); // Obtain tipid for attemptid, if attemptid is available. TaskID tipidObj = (attemptidObj == null) ? TaskID.forName(request.getParameter("tipid")) : attemptidObj.getTaskID(); if (tipidObj == null) { out.print("tipid sent is not valid.
\n"); return; } // Obtain jobid from tipid final JobID jobidObj = tipidObj.getJobID(); String jobid = jobidObj.toString(); JobWithViewAccessCheck myJob = JSPUtil.checkAccessAndGetJob(tracker, jobidObj, request, response); if (!myJob.isViewJobAllowed()) { return; // user is not authorized to view this job } JobInProgress job = myJob.getJob(); if (job == null) { out.print("Job " + jobid + " not found.
\n"); return; } boolean privateActions = JSPUtil.privateActionsAllowed(tracker.conf); if (privateActions) { String action = request.getParameter("action"); if (action != null) { String user = request.getRemoteUser(); UserGroupInformation ugi = null; if (user != null) { ugi = UserGroupInformation.createRemoteUser(user); } if (action.equalsIgnoreCase("confirm")) { String subAction = request.getParameter("subaction"); if (subAction == null) subAction = "fail-task"; printConfirm(out, attemptid, subAction); return; } else if (action.equalsIgnoreCase("kill-task") && request.getMethod().equalsIgnoreCase("POST")) { if (ugi != null) { try { ugi.doAs(new PrivilegedExceptionAction() { public Void run() throws IOException{ tracker.killTask(attemptidObj, false);// checks job modify permission return null; } }); } catch(AccessControlException e) { String errMsg = "User " + user + " failed to kill task " + attemptidObj + "!

" + e.getMessage() + "
Go back to Job
"; JSPUtil.setErrorAndForward(errMsg, request, response); return; } } else {// no authorization needed tracker.killTask(attemptidObj, false); } //redirect again so that refreshing the page will not attempt to rekill the task response.sendRedirect("/taskdetails.jsp?subaction=kill-task" + "&tipid=" + tipidObj.toString()); } else if (action.equalsIgnoreCase("fail-task") && request.getMethod().equalsIgnoreCase("POST")) { if (ugi != null) { try { ugi.doAs(new PrivilegedExceptionAction() { public Void run() throws IOException{ tracker.killTask(attemptidObj, true);// checks job modify permission return null; } }); } catch(AccessControlException e) { String errMsg = "User " + user + " failed to fail task " + attemptidObj + "!

" + e.getMessage() + "
Go back to Job
"; JSPUtil.setErrorAndForward(errMsg, request, response); return; } } else {// no authorization needed tracker.killTask(attemptidObj, true); } response.sendRedirect("/taskdetails.jsp?subaction=fail-task" + "&tipid=" + tipidObj.toString()); } } } TaskInProgress tip = job.getTaskInProgress(tipidObj); TaskStatus[] ts = null; boolean isCleanupOrSetup = false; if (tip != null) { ts = tip.getTaskStatuses(); isCleanupOrSetup = tip.isJobCleanupTask(); if (!isCleanupOrSetup) { isCleanupOrSetup = tip.isJobSetupTask(); } } %> Hadoop Task Details

Job <%=jobid%>


All Task Attempts

<% if (ts == null || ts.length == 0) { %>

No Task Attempts found

<% } else { %> <% if (!ts[0].getIsMap() && !isCleanupOrSetup) { %> <% } %> <% for (int i = 0; i < ts.length; i++) { TaskStatus status = ts[i]; String taskTrackerName = status.getTaskTracker(); TaskTrackerStatus taskTracker = tracker.getTaskTrackerStatus(taskTrackerName); out.print(""); String taskAttemptTracker = null; String cleanupTrackerName = null; TaskTrackerStatus cleanupTracker = null; String cleanupAttemptTracker = null; boolean hasCleanupAttempt = false; if (tip != null && tip.isCleanupAttempt(status.getTaskID())) { cleanupTrackerName = tip.machineWhereCleanupRan(status.getTaskID()); cleanupTracker = tracker.getTaskTrackerStatus(cleanupTrackerName); if (cleanupTracker != null) { cleanupAttemptTracker = "http://" + cleanupTracker.getHost() + ":" + cleanupTracker.getHttpPort(); } hasCleanupAttempt = true; } out.print(""); out.print(""); out.print(""); out.print(""); if (!ts[i].getIsMap() && !isCleanupOrSetup) { out.print(""); out.println(""); } out.println(""); out.print(""); out.print(""); out.print(""); } %>
Task AttemptsMachineStatusProgressStart TimeShuffle FinishedSort FinishedFinish TimeErrorsTask LogsCountersActions
" + status.getTaskID() + ""); if (hasCleanupAttempt) { out.print("Task attempt: "); } if (taskTracker == null) { out.print(taskTrackerName); } else { taskAttemptTracker = "http://" + taskTracker.getHost() + ":" + taskTracker.getHttpPort(); out.print("" + tracker.getNode(taskTracker.getHost()) + ""); } if (hasCleanupAttempt) { out.print("
Cleanup Attempt: "); if (cleanupAttemptTracker == null ) { out.print(cleanupTrackerName); } else { out.print("" + tracker.getNode(cleanupTracker.getHost()) + ""); } } out.print("
" + status.getRunState() + "" + StringUtils.formatPercent(status.getProgress(), 2) + ServletUtil.percentageGraph(status.getProgress() * 100f, 80) + "" + StringUtils.getFormattedTimeWithDiff(dateFormat, status .getStartTime(), 0) + "" + StringUtils.getFormattedTimeWithDiff(dateFormat, status .getShuffleFinishTime(), status.getStartTime()) + "" + StringUtils.getFormattedTimeWithDiff(dateFormat, status .getSortFinishTime(), status.getShuffleFinishTime()) + "" + StringUtils.getFormattedTimeWithDiff(dateFormat, status .getFinishTime(), status.getStartTime()) + "
");
        String [] failures = tracker.getTaskDiagnostics(status.getTaskID());
        if (failures == null) {
          out.print(" ");
        } else {
          for(int j = 0 ; j < failures.length ; j++){
            out.print(HtmlQuoting.quoteHtmlChars(failures[j]));
            if (j < (failures.length - 1)) {
              out.print("\n-------\n");
            }
          }
        }
        out.print("
"); String taskLogUrl = null; if (taskTracker != null ) { taskLogUrl = TaskLogServlet.getTaskLogUrl(taskTracker.getHost(), String.valueOf(taskTracker.getHttpPort()), status.getTaskID().toString()); } if (hasCleanupAttempt) { out.print("Task attempt:
"); } if (taskLogUrl == null) { out.print("n/a"); } else { String tailFourKBUrl = taskLogUrl + "&start=-4097"; String tailEightKBUrl = taskLogUrl + "&start=-8193"; String entireLogUrl = taskLogUrl + "&all=true"; out.print("Last 4KB
"); out.print("Last 8KB
"); out.print("All
"); } if (hasCleanupAttempt) { out.print("Cleanup attempt:
"); taskLogUrl = null; if (cleanupTracker != null ) { taskLogUrl = TaskLogServlet.getTaskLogUrl(cleanupTracker.getHost(), String.valueOf(cleanupTracker.getHttpPort()), status.getTaskID().toString()); } if (taskLogUrl == null) { out.print("n/a"); } else { String tailFourKBUrl = taskLogUrl + "&start=-4097&cleanup=true"; String tailEightKBUrl = taskLogUrl + "&start=-8193&cleanup=true"; String entireLogUrl = taskLogUrl + "&all=true&cleanup=true"; out.print("Last 4KB
"); out.print("Last 8KB
"); out.print("All
"); } } out.print("
" + "" + ((status.getCounters() != null) ? status.getCounters().size() : 0) + ""); if (privateActions && status.getRunState() == TaskStatus.State.RUNNING) { out.print(" Kill "); out.print("
Fail "); } else out.print("
 
"); out.println("
<% if (ts[0].getIsMap() && !isCleanupOrSetup) { %>

Input Split Locations

<% for (String split: StringUtils.split(tracker.getTip( tipidObj).getSplitNodes())) { out.println(""); } %>
" + split + "
<% } } %>
Go back to the job
Go back to JobTracker
<% out.println(ServletUtil.htmlFooter()); %> <% } // if (response_format != null) %>