From 022f49d59e404678d0f322bb1b67208f3c17b7ef Mon Sep 17 00:00:00 2001 From: Tsuyoshi Ozawa Date: Tue, 26 May 2015 23:59:02 +0900 Subject: [PATCH] MAPREDUCE-6364. Add a Kill link to Task Attempts page. Contributed by Ryu Kobayashi. --- hadoop-mapreduce-project/CHANGES.txt | 3 + .../mapreduce/v2/app/webapp/AttemptsPage.java | 5 +- .../mapreduce/v2/app/webapp/TaskPage.java | 89 +++++++++++++++---- .../org/apache/hadoop/mapreduce/MRConfig.java | 7 ++ 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/hadoop-mapreduce-project/CHANGES.txt b/hadoop-mapreduce-project/CHANGES.txt index 08e5e3453e..40ef037027 100644 --- a/hadoop-mapreduce-project/CHANGES.txt +++ b/hadoop-mapreduce-project/CHANGES.txt @@ -267,6 +267,9 @@ Release 2.8.0 - UNRELEASED MAPREDUCE-6284. Add Task Attempt State API to MapReduce Application Master REST API. (Ryu Kobayashi via ozawa) + MAPREDUCE-6364. Add a "Kill" link to Task Attempts page. (Ryu Kobayashi + via ozawa) + IMPROVEMENTS MAPREDUCE-6291. Correct mapred queue usage command. diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AttemptsPage.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AttemptsPage.java index 92ae7b6f84..5dda01e38a 100644 --- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AttemptsPage.java +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AttemptsPage.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.mapreduce.v2.api.records.TaskAttemptId; import org.apache.hadoop.mapreduce.v2.api.records.TaskAttemptState; import org.apache.hadoop.mapreduce.v2.api.records.TaskType; @@ -40,8 +41,8 @@ import com.google.inject.Inject; public class AttemptsPage extends TaskPage { static class FewAttemptsBlock extends TaskPage.AttemptsBlock { @Inject - FewAttemptsBlock(App ctx) { - super(ctx); + FewAttemptsBlock(App ctx, Configuration conf) { + super(ctx, conf); } @Override diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/TaskPage.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/TaskPage.java index e293fd2220..758b02c022 100644 --- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/TaskPage.java +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/TaskPage.java @@ -27,6 +27,8 @@ import static org.apache.hadoop.yarn.webapp.view.JQueryUI.tableInit; import java.util.Collection; import org.apache.commons.lang.StringEscapeUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.mapreduce.MRConfig; import org.apache.hadoop.mapreduce.v2.app.job.TaskAttempt; import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TaskAttemptInfo; import org.apache.hadoop.mapreduce.v2.util.MRWebAppUtil; @@ -35,6 +37,8 @@ import org.apache.hadoop.yarn.webapp.SubView; 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.hamlet.Hamlet.THEAD; +import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TR; import org.apache.hadoop.yarn.webapp.view.HtmlBlock; import com.google.inject.Inject; @@ -43,10 +47,15 @@ public class TaskPage extends AppView { static class AttemptsBlock extends HtmlBlock { final App app; + final boolean enableUIActions; + private String stateURLFormat; @Inject - AttemptsBlock(App ctx) { + AttemptsBlock(App ctx, Configuration conf) { app = ctx; + this.enableUIActions = + conf.getBoolean(MRConfig.MASTER_WEBAPP_UI_ACTIONS_ENABLED, + MRConfig.DEFAULT_MASTER_WEBAPP_UI_ACTIONS_ENABLED); } @Override @@ -56,21 +65,58 @@ public class TaskPage extends AppView { h2($(TITLE)); return; } - TBODY> tbody = html. - table("#attempts"). - thead(). - tr(). - th(".id", "Attempt"). - th(".progress", "Progress"). - th(".state", "State"). - th(".status", "Status"). - th(".node", "Node"). - th(".logs", "Logs"). - th(".tsh", "Started"). - th(".tsh", "Finished"). - th(".tsh", "Elapsed"). - th(".note", "Note")._()._(). - tbody(); + + if (enableUIActions) { + // Kill task attempt + String appID = app.getJob().getID().getAppId().toString(); + String jobID = app.getJob().getID().toString(); + String taskID = app.getTask().getID().toString(); + stateURLFormat = + String.format("/proxy/%s/ws/v1/mapreduce/jobs/%s/tasks/%s/" + + "attempts", appID, jobID, taskID) + "/%s/state"; + + String current = + String.format("/proxy/%s/mapreduce/task/%s", appID, taskID); + + StringBuilder script = new StringBuilder(); + script.append("function confirmAction(stateURL) {") + .append(" b = confirm(\"Are you sure?\");") + .append(" if (b == true) {") + .append(" $.ajax({") + .append(" type: 'PUT',") + .append(" url: stateURL,") + .append(" contentType: 'application/json',") + .append(" data: '{\"state\":\"KILLED\"}',") + .append(" dataType: 'json'") + .append(" }).done(function(data){") + .append(" setTimeout(function(){") + .append(" location.href = '").append(current).append("';") + .append(" }, 1000);") + .append(" }).fail(function(data){") + .append(" console.log(data);") + .append(" });") + .append(" }") + .append("}"); + + html.script().$type("text/javascript")._(script.toString())._(); + } + + TR>> tr = html.table("#attempts").thead().tr(); + tr.th(".id", "Attempt"). + th(".progress", "Progress"). + th(".state", "State"). + th(".status", "Status"). + th(".node", "Node"). + th(".logs", "Logs"). + th(".tsh", "Started"). + th(".tsh", "Finished"). + th(".tsh", "Elapsed"). + th(".note", "Note"); + if (enableUIActions) { + tr.th(".actions", "Actions"); + } + + TBODY> tbody = tr._()._().tbody(); // Write all the data into a JavaScript array of arrays for JQuery // DataTables to display StringBuilder attemptsTableData = new StringBuilder("[\n"); @@ -103,7 +149,16 @@ public class TaskPage extends AppView { .append(ta.getFinishTime()).append("\",\"") .append(ta.getElapsedTime()).append("\",\"") .append(StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml( - diag))).append("\"],\n"); + diag))); + if (enableUIActions) { + attemptsTableData.append("\",\"") + .append("Kill") + .append("\"],\n"); + } else { + attemptsTableData.append("\"],\n"); + } } //Remove the last comma and close off the array of arrays if(attemptsTableData.charAt(attemptsTableData.length() - 2) == ',') { diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/MRConfig.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/MRConfig.java index a76683d9ad..e85c8935e1 100644 --- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/MRConfig.java +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/MRConfig.java @@ -124,5 +124,12 @@ public interface MRConfig { @Unstable public static final boolean DEFAULT_MAPREDUCE_APP_SUBMISSION_CROSS_PLATFORM = false; + + /** + * Enable application master webapp ui actions. + */ + String MASTER_WEBAPP_UI_ACTIONS_ENABLED = + "mapreduce.webapp.ui-actions.enabled"; + boolean DEFAULT_MASTER_WEBAPP_UI_ACTIONS_ENABLED = true; }