瀏覽代碼

MAPREDUCE-6787. Allow job_conf.xml to be downloadable on the job overview page in JHS (haibochen via rkanter)

Robert Kanter 8 年之前
父節點
當前提交
c87b3a448a

+ 34 - 0
hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AppController.java

@@ -323,6 +323,40 @@ public class AppController extends Controller implements AMParams {
     render(confPage());
     render(confPage());
   }
   }
 
 
+  /**
+   * Handle requests to download the job configuration.
+   */
+  public void downloadConf() {
+    try {
+      requireJob();
+    } catch (Exception e) {
+      renderText(e.getMessage());
+      return;
+    }
+    writeJobConf();
+  }
+
+  private void writeJobConf() {
+    String jobId = $(JOB_ID);
+    assert(!jobId.isEmpty());
+
+    JobId jobID = MRApps.toJobID($(JOB_ID));
+    Job job = app.context.getJob(jobID);
+    assert(job != null);
+
+    try {
+      Configuration jobConf = job.loadConfFile();
+      response().setContentType("text/xml");
+      response().setHeader("Content-Disposition",
+          "attachment; filename=" + jobId + ".xml");
+      jobConf.writeXml(writer());
+    } catch (IOException e) {
+      LOG.error("Error reading/writing job" +
+          " conf file for job: " + jobId, e);
+      renderText(e.getMessage());
+    }
+  }
+
   /**
   /**
    * Render a BAD_REQUEST error.
    * Render a BAD_REQUEST error.
    * @param s the error message to include.
    * @param s the error message to include.

+ 1 - 1
hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/ConfBlock.java

@@ -70,7 +70,7 @@ public class ConfBlock extends HtmlBlock {
     try {
     try {
       ConfInfo info = new ConfInfo(job);
       ConfInfo info = new ConfInfo(job);
 
 
-      html.div().h3(confPath.toString())._();
+      html.div().a("/jobhistory/downloadconf/" + jid, confPath.toString());
       TBODY<TABLE<Hamlet>> tbody = html.
       TBODY<TABLE<Hamlet>> tbody = html.
         // Tasks table
         // Tasks table
       table("#conf").
       table("#conf").

+ 14 - 0
hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/webapp/TestAppController.java

@@ -24,6 +24,7 @@ import java.util.Iterator;
 
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.mapreduce.JobACL;
 import org.apache.hadoop.mapreduce.JobACL;
 import org.apache.hadoop.mapreduce.v2.api.records.JobId;
 import org.apache.hadoop.mapreduce.v2.api.records.JobId;
 import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
 import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
@@ -59,6 +60,8 @@ public class TestAppController {
     Task task = mock(Task.class);
     Task task = mock(Task.class);
 
 
     when(job.getTask(any(TaskId.class))).thenReturn(task);
     when(job.getTask(any(TaskId.class))).thenReturn(task);
+    when(job.loadConfFile()).thenReturn(new Configuration());
+    when(job.getConfFile()).thenReturn(new Path("/"));
 
 
     JobId jobID = MRApps.toJobID("job_01_01");
     JobId jobID = MRApps.toJobID("job_01_01");
     when(context.getJob(jobID)).thenReturn(job);
     when(context.getJob(jobID)).thenReturn(job);
@@ -265,6 +268,17 @@ public class TestAppController {
     assertEquals(JobConfPage.class, appController.getClazz());
     assertEquals(JobConfPage.class, appController.getClazz());
   }
   }
 
 
+  /**
+   * Test downloadConf request handling.
+   */
+  @Test
+  public void testDownloadConfiguration() {
+    appController.downloadConf();
+    String jobConfXml = appController.getData();
+    assertTrue("Error downloading the job configuration file.",
+        !jobConfXml.contains("Error"));
+  }
+
   /**
   /**
    *   Test method 'conf'. Should set AttemptsPage class for rendering or print information about error
    *   Test method 'conf'. Should set AttemptsPage class for rendering or print information about error
    */
    */

+ 2 - 0
hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/HsWebApp.java

@@ -50,6 +50,8 @@ public class HsWebApp extends WebApp implements AMParams {
     route("/app", HsController.class);
     route("/app", HsController.class);
     route(pajoin("/job", JOB_ID), HsController.class, "job");
     route(pajoin("/job", JOB_ID), HsController.class, "job");
     route(pajoin("/conf", JOB_ID), HsController.class, "conf");
     route(pajoin("/conf", JOB_ID), HsController.class, "conf");
+    routeWithoutDefaultView(pajoin("/downloadconf", JOB_ID),
+        HsController.class, "downloadConf");
     route(pajoin("/jobcounters", JOB_ID), HsController.class, "jobCounters");
     route(pajoin("/jobcounters", JOB_ID), HsController.class, "jobCounters");
     route(pajoin("/singlejobcounter",JOB_ID, COUNTER_GROUP, COUNTER_NAME),
     route(pajoin("/singlejobcounter",JOB_ID, COUNTER_GROUP, COUNTER_NAME),
         HsController.class, "singleJobCounter");
         HsController.class, "singleJobCounter");

+ 19 - 4
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/Router.java

@@ -74,17 +74,32 @@ class Router {
 
 
   final TreeMap<String, Dest> routes = Maps.newTreeMap(); // path->dest
   final TreeMap<String, Dest> routes = Maps.newTreeMap(); // path->dest
 
 
+  synchronized Dest add(WebApp.HTTP httpMethod, String path,
+                        Class<? extends Controller> cls,
+                        String action, List<String> names){
+    return addWithOptionalDefaultView(
+        httpMethod, path, cls, action, names, true);
+  }
+
+  synchronized Dest addWithoutDefaultView(WebApp.HTTP httpMethod,
+      String path, Class<? extends Controller> cls, String action,
+      List<String> names){
+    return addWithOptionalDefaultView(httpMethod, path, cls, action,
+        names, false);
+  }
   /**
   /**
    * Add a route to the router.
    * Add a route to the router.
    * e.g., add(GET, "/foo/show", FooController.class, "show", [name...]);
    * e.g., add(GET, "/foo/show", FooController.class, "show", [name...]);
    * The name list is from /foo/show/:name/...
    * The name list is from /foo/show/:name/...
    */
    */
-  synchronized Dest add(WebApp.HTTP httpMethod, String path,
-                        Class<? extends Controller> cls,
-                        String action, List<String> names) {
+  synchronized Dest addWithOptionalDefaultView(WebApp.HTTP httpMethod,
+      String path, Class<? extends Controller> cls,
+      String action, List<String> names, boolean defaultViewNeeded) {
     LOG.debug("adding {}({})->{}#{}", new Object[]{path, names, cls, action});
     LOG.debug("adding {}({})->{}#{}", new Object[]{path, names, cls, action});
     Dest dest = addController(httpMethod, path, cls, action, names);
     Dest dest = addController(httpMethod, path, cls, action, names);
-    addDefaultView(dest);
+    if (defaultViewNeeded) {
+      addDefaultView(dest);
+    }
     return dest;
     return dest;
   }
   }
 
 

+ 13 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApp.java

@@ -210,6 +210,19 @@ public abstract class WebApp extends ServletModule {
                res.subList(R_PARAMS, res.size()));
                res.subList(R_PARAMS, res.size()));
   }
   }
 
 
+  /**
+   * Setup of a webapp serving route without default views added to the page.
+   * @param pathSpec  the path spec in the form of /controller/action/:args etc.
+   * @param cls the controller class
+   * @param action the controller method
+   */
+  public void routeWithoutDefaultView(String pathSpec,
+                    Class<? extends Controller> cls, String action) {
+    List<String> res = parseRoute(pathSpec);
+    router.addWithoutDefaultView(HTTP.GET, res.get(R_PATH), cls, action,
+        res.subList(R_PARAMS, res.size()));
+  }
+
   public void route(String pathSpec, Class<? extends Controller> cls,
   public void route(String pathSpec, Class<? extends Controller> cls,
                     String action) {
                     String action) {
     route(HTTP.GET, pathSpec, cls, action);
     route(HTTP.GET, pathSpec, cls, action);