From 87b969c83541c6719abcc1dabc38dc41704876ee Mon Sep 17 00:00:00 2001 From: Vinod Kumar Vavilapalli Date: Tue, 27 Sep 2011 17:03:19 +0000 Subject: [PATCH] MAPREDUCE-2999. Fix YARN webapp framework to properly filter servlet paths. Contributed by Thomas Graves. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1176469 13f79535-47bb-0310-9956-ffa450edef68 --- hadoop-mapreduce-project/CHANGES.txt | 3 +++ .../apache/hadoop/yarn/webapp/Dispatcher.java | 9 +++++++ .../org/apache/hadoop/yarn/webapp/WebApp.java | 25 ++++++++++++++++- .../apache/hadoop/yarn/webapp/WebApps.java | 11 +++++++- .../apache/hadoop/yarn/webapp/TestWebApp.java | 27 +++++++++++++++++++ .../resourcemanager/rmnode/RMNodeImpl.java | 2 +- 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/hadoop-mapreduce-project/CHANGES.txt b/hadoop-mapreduce-project/CHANGES.txt index 61cebeeff6..31b90d0a97 100644 --- a/hadoop-mapreduce-project/CHANGES.txt +++ b/hadoop-mapreduce-project/CHANGES.txt @@ -1444,6 +1444,9 @@ Release 0.23.0 - Unreleased MAPREDUCE-3067. Ensure exit-code is set correctly for containers. (Hitesh Shah via acmurthy) + MAPREDUCE-2999. Fix YARN webapp framework to properly filter servlet + paths. (Thomas Graves via vinodkv) + Release 0.22.0 - Unreleased INCOMPATIBLE CHANGES diff --git a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/Dispatcher.java b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/Dispatcher.java index ef8ab976ef..e404fe5a72 100644 --- a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/Dispatcher.java +++ b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/Dispatcher.java @@ -84,6 +84,15 @@ public void service(HttpServletRequest req, HttpServletResponse res) prepareToExit(); return; } + // if they provide a redirectPath go there instead of going to + // "/" so that filters can differentiate the webapps. + if (uri.equals("/")) { + String redirectPath = webApp.getRedirectPath(); + if (redirectPath != null && !redirectPath.isEmpty()) { + res.sendRedirect(redirectPath); + return; + } + } String method = req.getMethod(); if (method.equals("OPTIONS")) { doOptions(req, res); diff --git a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApp.java b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApp.java index b9afe81ca8..f83843e97e 100644 --- a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApp.java +++ b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApp.java @@ -26,6 +26,7 @@ import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.ServletModule; +import java.util.ArrayList; import java.util.List; import org.apache.hadoop.conf.Configuration; @@ -44,6 +45,9 @@ public abstract class WebApp extends ServletModule { public enum HTTP { GET, POST, HEAD, PUT, DELETE }; private volatile String name; + private volatile List servePathSpecs = new ArrayList(); + // path to redirect to if user goes to "/" + private volatile String redirectPath; private volatile Configuration conf; private volatile HttpServer httpServer; private volatile GuiceFilter guiceFilter; @@ -98,6 +102,22 @@ public void joinThread() { public String name() { return this.name; } + void addServePathSpec(String path) { this.servePathSpecs.add(path); } + + public String[] getServePathSpecs() { + return this.servePathSpecs.toArray(new String[this.servePathSpecs.size()]); + } + + /** + * Set a path to redirect the user to if they just go to "/". For + * instance "/" goes to "/yarn/apps". This allows the filters to + * more easily differentiate the different webapps. + * @param path the path to redirect to + */ + void setRedirectPath(String path) { this.redirectPath = path; } + + public String getRedirectPath() { return this.redirectPath; } + void setHostClass(Class cls) { router.setHostClass(cls); } @@ -109,7 +129,10 @@ void setGuiceFilter(GuiceFilter instance) { @Override public void configureServlets() { setup(); - serve("/", "/__stop", StringHelper.join('/', name, '*')).with(Dispatcher.class); + serve("/", "/__stop").with(Dispatcher.class); + for (String path : this.servePathSpecs) { + serve(path).with(Dispatcher.class); + } } /** diff --git a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java index 85b88d16cc..b521799968 100644 --- a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java +++ b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java @@ -113,6 +113,14 @@ public void setup() { }; } webapp.setName(name); + String basePath = "/" + name; + webapp.setRedirectPath(basePath); + if (basePath.equals("/")) { + webapp.addServePathSpec("/*"); + } else { + webapp.addServePathSpec(basePath); + webapp.addServePathSpec(basePath + "/*"); + } if (conf == null) { conf = new Configuration(); } @@ -142,7 +150,8 @@ public void setup() { } } HttpServer server = - new HttpServer(name, bindAddress, port, findPort, conf); + new HttpServer(name, bindAddress, port, findPort, conf, + webapp.getServePathSpecs()); server.addGlobalFilter("guice", GuiceFilter.class.getName(), null); webapp.setConf(conf); webapp.setHttpServer(server); diff --git a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/TestWebApp.java b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/TestWebApp.java index db84f32cf6..31b2aaa2ed 100644 --- a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/TestWebApp.java +++ b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/TestWebApp.java @@ -18,6 +18,7 @@ package org.apache.hadoop.yarn.webapp; +import org.apache.commons.lang.ArrayUtils; import org.apache.hadoop.yarn.MockApps; import org.apache.hadoop.yarn.webapp.Controller; import org.apache.hadoop.yarn.webapp.WebApp; @@ -148,6 +149,32 @@ public void render(Page.HTML<_> html) { app.stop(); } + @Test public void testServePaths() { + WebApp app = WebApps.$for("test", this).start(); + assertEquals("/test", app.getRedirectPath()); + String[] expectedPaths = { "/test", "/test/*" }; + String[] pathSpecs = app.getServePathSpecs(); + + assertEquals(2, pathSpecs.length); + for(int i = 0; i < expectedPaths.length; i++) { + assertTrue(ArrayUtils.contains(pathSpecs, expectedPaths[i])); + } + app.stop(); + } + + @Test public void testServePathsNoName() { + WebApp app = WebApps.$for("", this).start(); + assertEquals("/", app.getRedirectPath()); + String[] expectedPaths = { "/*" }; + String[] pathSpecs = app.getServePathSpecs(); + + assertEquals(1, pathSpecs.length); + for(int i = 0; i < expectedPaths.length; i++) { + assertTrue(ArrayUtils.contains(pathSpecs, expectedPaths[i])); + } + app.stop(); + } + @Test public void testDefaultRoutes() throws Exception { WebApp app = WebApps.$for("test", this).start(); String baseUrl = baseUrl(app); diff --git a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmnode/RMNodeImpl.java b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmnode/RMNodeImpl.java index 81de047bc0..3b3864a541 100644 --- a/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmnode/RMNodeImpl.java +++ b/hadoop-mapreduce-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/rmnode/RMNodeImpl.java @@ -144,7 +144,7 @@ public RMNodeImpl(NodeId nodeId, RMContext context, String hostName, this.httpPort = httpPort; this.totalCapability = capability; this.nodeAddress = hostName + ":" + cmPort; - this.httpAddress = hostName + ":" + httpPort;; + this.httpAddress = hostName + ":" + httpPort; this.node = node; this.nodeHealthStatus.setIsNodeHealthy(true); this.nodeHealthStatus.setHealthReport("Healthy");