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
This commit is contained in:
Vinod Kumar Vavilapalli 2011-09-27 17:03:19 +00:00
parent 6507a0bc35
commit 87b969c835
6 changed files with 74 additions and 3 deletions

View File

@ -1444,6 +1444,9 @@ Release 0.23.0 - Unreleased
MAPREDUCE-3067. Ensure exit-code is set correctly for containers. (Hitesh MAPREDUCE-3067. Ensure exit-code is set correctly for containers. (Hitesh
Shah via acmurthy) Shah via acmurthy)
MAPREDUCE-2999. Fix YARN webapp framework to properly filter servlet
paths. (Thomas Graves via vinodkv)
Release 0.22.0 - Unreleased Release 0.22.0 - Unreleased
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -84,6 +84,15 @@ public class Dispatcher extends HttpServlet {
prepareToExit(); prepareToExit();
return; 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(); String method = req.getMethod();
if (method.equals("OPTIONS")) { if (method.equals("OPTIONS")) {
doOptions(req, res); doOptions(req, res);

View File

@ -26,6 +26,7 @@ import com.google.inject.Provides;
import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.GuiceFilter;
import com.google.inject.servlet.ServletModule; import com.google.inject.servlet.ServletModule;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
@ -44,6 +45,9 @@ public abstract class WebApp extends ServletModule {
public enum HTTP { GET, POST, HEAD, PUT, DELETE }; public enum HTTP { GET, POST, HEAD, PUT, DELETE };
private volatile String name; private volatile String name;
private volatile List<String> servePathSpecs = new ArrayList<String>();
// path to redirect to if user goes to "/"
private volatile String redirectPath;
private volatile Configuration conf; private volatile Configuration conf;
private volatile HttpServer httpServer; private volatile HttpServer httpServer;
private volatile GuiceFilter guiceFilter; private volatile GuiceFilter guiceFilter;
@ -98,6 +102,22 @@ public abstract class WebApp extends ServletModule {
public String name() { return this.name; } 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) { void setHostClass(Class<?> cls) {
router.setHostClass(cls); router.setHostClass(cls);
} }
@ -109,7 +129,10 @@ public abstract class WebApp extends ServletModule {
@Override @Override
public void configureServlets() { public void configureServlets() {
setup(); setup();
serve("/", "/__stop", StringHelper.join('/', name, '*')).with(Dispatcher.class); serve("/", "/__stop").with(Dispatcher.class);
for (String path : this.servePathSpecs) {
serve(path).with(Dispatcher.class);
}
} }
/** /**

View File

@ -113,6 +113,14 @@ public class WebApps {
}; };
} }
webapp.setName(name); webapp.setName(name);
String basePath = "/" + name;
webapp.setRedirectPath(basePath);
if (basePath.equals("/")) {
webapp.addServePathSpec("/*");
} else {
webapp.addServePathSpec(basePath);
webapp.addServePathSpec(basePath + "/*");
}
if (conf == null) { if (conf == null) {
conf = new Configuration(); conf = new Configuration();
} }
@ -142,7 +150,8 @@ public class WebApps {
} }
} }
HttpServer server = 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); server.addGlobalFilter("guice", GuiceFilter.class.getName(), null);
webapp.setConf(conf); webapp.setConf(conf);
webapp.setHttpServer(server); webapp.setHttpServer(server);

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.yarn.webapp; package org.apache.hadoop.yarn.webapp;
import org.apache.commons.lang.ArrayUtils;
import org.apache.hadoop.yarn.MockApps; import org.apache.hadoop.yarn.MockApps;
import org.apache.hadoop.yarn.webapp.Controller; import org.apache.hadoop.yarn.webapp.Controller;
import org.apache.hadoop.yarn.webapp.WebApp; import org.apache.hadoop.yarn.webapp.WebApp;
@ -148,6 +149,32 @@ public class TestWebApp {
app.stop(); 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 { @Test public void testDefaultRoutes() throws Exception {
WebApp app = WebApps.$for("test", this).start(); WebApp app = WebApps.$for("test", this).start();
String baseUrl = baseUrl(app); String baseUrl = baseUrl(app);

View File

@ -144,7 +144,7 @@ public class RMNodeImpl implements RMNode, EventHandler<RMNodeEvent> {
this.httpPort = httpPort; this.httpPort = httpPort;
this.totalCapability = capability; this.totalCapability = capability;
this.nodeAddress = hostName + ":" + cmPort; this.nodeAddress = hostName + ":" + cmPort;
this.httpAddress = hostName + ":" + httpPort;; this.httpAddress = hostName + ":" + httpPort;
this.node = node; this.node = node;
this.nodeHealthStatus.setIsNodeHealthy(true); this.nodeHealthStatus.setIsNodeHealthy(true);
this.nodeHealthStatus.setHealthReport("Healthy"); this.nodeHealthStatus.setHealthReport("Healthy");