PageRenderTime 3883ms CodeModel.GetById 30ms RepoModel.GetById 23ms app.codeStats 0ms

/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java

https://gitlab.com/xiaoliuliu2050/hadoop
Java | 355 lines | 260 code | 34 blank | 61 comment | 41 complexity | 5f0829018c604c31a9e9c420b8bb59fb MD5 | raw file
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.apache.hadoop.yarn.webapp;
  19. import static com.google.common.base.Preconditions.checkNotNull;
  20. import java.io.IOException;
  21. import java.net.ConnectException;
  22. import java.net.URI;
  23. import java.net.URL;
  24. import java.util.ArrayList;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.List;
  28. import java.util.Map;
  29. import javax.servlet.http.HttpServlet;
  30. import org.apache.commons.lang.StringUtils;
  31. import org.apache.hadoop.classification.InterfaceAudience;
  32. import org.apache.hadoop.conf.Configuration;
  33. import org.apache.hadoop.http.HttpConfig.Policy;
  34. import org.apache.hadoop.http.HttpConfig;
  35. import org.apache.hadoop.http.HttpServer2;
  36. import org.apache.hadoop.security.UserGroupInformation;
  37. import org.apache.hadoop.yarn.conf.YarnConfiguration;
  38. import org.apache.hadoop.yarn.security.AdminACLsManager;
  39. import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
  40. import org.slf4j.Logger;
  41. import org.slf4j.LoggerFactory;
  42. import com.google.inject.AbstractModule;
  43. import com.google.inject.Guice;
  44. import com.google.inject.Injector;
  45. import com.google.inject.servlet.GuiceFilter;
  46. /**
  47. * Helpers to create an embedded webapp.
  48. *
  49. * <h4>Quick start:</h4>
  50. * <pre>
  51. * WebApp wa = WebApps.$for(myApp).start();</pre>
  52. * Starts a webapp with default routes binds to 0.0.0.0 (all network interfaces)
  53. * on an ephemeral port, which can be obtained with:<pre>
  54. * int port = wa.port();</pre>
  55. * <h4>With more options:</h4>
  56. * <pre>
  57. * WebApp wa = WebApps.$for(myApp).at(address, port).
  58. * with(configuration).
  59. * start(new WebApp() {
  60. * &#064;Override public void setup() {
  61. * route("/foo/action", FooController.class);
  62. * route("/foo/:id", FooController.class, "show");
  63. * }
  64. * });</pre>
  65. */
  66. @InterfaceAudience.LimitedPrivate({"YARN", "MapReduce"})
  67. public class WebApps {
  68. static final Logger LOG = LoggerFactory.getLogger(WebApps.class);
  69. public static class Builder<T> {
  70. static class ServletStruct {
  71. public Class<? extends HttpServlet> clazz;
  72. public String name;
  73. public String spec;
  74. }
  75. final String name;
  76. final String wsName;
  77. final Class<T> api;
  78. final T application;
  79. String bindAddress = "0.0.0.0";
  80. int port = 0;
  81. boolean findPort = false;
  82. Configuration conf;
  83. Policy httpPolicy = null;
  84. boolean devMode = false;
  85. private String spnegoPrincipalKey;
  86. private String spnegoKeytabKey;
  87. private final HashSet<ServletStruct> servlets = new HashSet<ServletStruct>();
  88. private final HashMap<String, Object> attributes = new HashMap<String, Object>();
  89. Builder(String name, Class<T> api, T application, String wsName) {
  90. this.name = name;
  91. this.api = api;
  92. this.application = application;
  93. this.wsName = wsName;
  94. }
  95. Builder(String name, Class<T> api, T application) {
  96. this(name, api, application, null);
  97. }
  98. public Builder<T> at(String bindAddress) {
  99. String[] parts = StringUtils.split(bindAddress, ':');
  100. if (parts.length == 2) {
  101. int port = Integer.parseInt(parts[1]);
  102. return at(parts[0], port, port == 0);
  103. }
  104. return at(bindAddress, 0, true);
  105. }
  106. public Builder<T> at(int port) {
  107. return at("0.0.0.0", port, port == 0);
  108. }
  109. public Builder<T> at(String address, int port, boolean findPort) {
  110. this.bindAddress = checkNotNull(address, "bind address");
  111. this.port = port;
  112. this.findPort = findPort;
  113. return this;
  114. }
  115. public Builder<T> withAttribute(String key, Object value) {
  116. attributes.put(key, value);
  117. return this;
  118. }
  119. public Builder<T> withServlet(String name, String pathSpec,
  120. Class<? extends HttpServlet> servlet) {
  121. ServletStruct struct = new ServletStruct();
  122. struct.clazz = servlet;
  123. struct.name = name;
  124. struct.spec = pathSpec;
  125. servlets.add(struct);
  126. return this;
  127. }
  128. public Builder<T> with(Configuration conf) {
  129. this.conf = conf;
  130. return this;
  131. }
  132. public Builder<T> withHttpPolicy(Configuration conf, Policy httpPolicy) {
  133. this.conf = conf;
  134. this.httpPolicy = httpPolicy;
  135. return this;
  136. }
  137. public Builder<T> withHttpSpnegoPrincipalKey(String spnegoPrincipalKey) {
  138. this.spnegoPrincipalKey = spnegoPrincipalKey;
  139. return this;
  140. }
  141. public Builder<T> withHttpSpnegoKeytabKey(String spnegoKeytabKey) {
  142. this.spnegoKeytabKey = spnegoKeytabKey;
  143. return this;
  144. }
  145. public Builder<T> inDevMode() {
  146. devMode = true;
  147. return this;
  148. }
  149. public WebApp start(WebApp webapp) {
  150. if (webapp == null) {
  151. webapp = new WebApp() {
  152. @Override
  153. public void setup() {
  154. // Defaults should be fine in usual cases
  155. }
  156. };
  157. }
  158. webapp.setName(name);
  159. webapp.setWebServices(wsName);
  160. String basePath = "/" + name;
  161. webapp.setRedirectPath(basePath);
  162. List<String> pathList = new ArrayList<String>();
  163. if (basePath.equals("/")) {
  164. webapp.addServePathSpec("/*");
  165. pathList.add("/*");
  166. } else {
  167. webapp.addServePathSpec(basePath);
  168. webapp.addServePathSpec(basePath + "/*");
  169. pathList.add(basePath + "/*");
  170. }
  171. if (wsName != null && !wsName.equals(basePath)) {
  172. if (wsName.equals("/")) {
  173. webapp.addServePathSpec("/*");
  174. pathList.add("/*");
  175. } else {
  176. webapp.addServePathSpec("/" + wsName);
  177. webapp.addServePathSpec("/" + wsName + "/*");
  178. pathList.add("/" + wsName + "/*");
  179. }
  180. }
  181. if (conf == null) {
  182. conf = new Configuration();
  183. }
  184. try {
  185. if (application != null) {
  186. webapp.setHostClass(application.getClass());
  187. } else {
  188. String cls = inferHostClass();
  189. LOG.debug("setting webapp host class to {}", cls);
  190. webapp.setHostClass(Class.forName(cls));
  191. }
  192. if (devMode) {
  193. if (port > 0) {
  194. try {
  195. new URL("http://localhost:"+ port +"/__stop").getContent();
  196. LOG.info("stopping existing webapp instance");
  197. Thread.sleep(100);
  198. } catch (ConnectException e) {
  199. LOG.info("no existing webapp instance found: {}", e.toString());
  200. } catch (Exception e) {
  201. // should not be fatal
  202. LOG.warn("error stopping existing instance: {}", e.toString());
  203. }
  204. } else {
  205. LOG.error("dev mode does NOT work with ephemeral port!");
  206. System.exit(1);
  207. }
  208. }
  209. String httpScheme;
  210. if (this.httpPolicy == null) {
  211. httpScheme = WebAppUtils.getHttpSchemePrefix(conf);
  212. } else {
  213. httpScheme =
  214. (httpPolicy == Policy.HTTPS_ONLY) ? WebAppUtils.HTTPS_PREFIX
  215. : WebAppUtils.HTTP_PREFIX;
  216. }
  217. HttpServer2.Builder builder = new HttpServer2.Builder()
  218. .setName(name)
  219. .addEndpoint(
  220. URI.create(httpScheme + bindAddress
  221. + ":" + port)).setConf(conf).setFindPort(findPort)
  222. .setACL(new AdminACLsManager(conf).getAdminAcl())
  223. .setPathSpec(pathList.toArray(new String[0]));
  224. boolean hasSpnegoConf = spnegoPrincipalKey != null
  225. && conf.get(spnegoPrincipalKey) != null && spnegoKeytabKey != null
  226. && conf.get(spnegoKeytabKey) != null;
  227. if (hasSpnegoConf) {
  228. builder.setUsernameConfKey(spnegoPrincipalKey)
  229. .setKeytabConfKey(spnegoKeytabKey)
  230. .setSecurityEnabled(UserGroupInformation.isSecurityEnabled());
  231. }
  232. if (httpScheme.equals(WebAppUtils.HTTPS_PREFIX)) {
  233. WebAppUtils.loadSslConfiguration(builder);
  234. }
  235. HttpServer2 server = builder.build();
  236. for(ServletStruct struct: servlets) {
  237. server.addServlet(struct.name, struct.spec, struct.clazz);
  238. }
  239. for(Map.Entry<String, Object> entry : attributes.entrySet()) {
  240. server.setAttribute(entry.getKey(), entry.getValue());
  241. }
  242. HttpServer2.defineFilter(server.getWebAppContext(), "guice",
  243. GuiceFilter.class.getName(), null, new String[] { "/*" });
  244. webapp.setConf(conf);
  245. webapp.setHttpServer(server);
  246. server.start();
  247. LOG.info("Web app /"+ name +" started at "+ server.getConnectorAddress(0).getPort());
  248. } catch (ClassNotFoundException e) {
  249. throw new WebAppException("Error starting http server", e);
  250. } catch (IOException e) {
  251. throw new WebAppException("Error starting http server", e);
  252. }
  253. Injector injector = Guice.createInjector(webapp, new AbstractModule() {
  254. @Override
  255. protected void configure() {
  256. if (api != null) {
  257. bind(api).toInstance(application);
  258. }
  259. }
  260. });
  261. LOG.info("Registered webapp guice modules");
  262. // save a guice filter instance for webapp stop (mostly for unit tests)
  263. webapp.setGuiceFilter(injector.getInstance(GuiceFilter.class));
  264. if (devMode) {
  265. injector.getInstance(Dispatcher.class).setDevMode(devMode);
  266. LOG.info("in dev mode!");
  267. }
  268. return webapp;
  269. }
  270. public WebApp start() {
  271. return start(null);
  272. }
  273. private String inferHostClass() {
  274. String thisClass = this.getClass().getName();
  275. Throwable t = new Throwable();
  276. for (StackTraceElement e : t.getStackTrace()) {
  277. if (e.getClassName().equals(thisClass)) continue;
  278. return e.getClassName();
  279. }
  280. LOG.warn("could not infer host class from", t);
  281. return thisClass;
  282. }
  283. }
  284. /**
  285. * Create a new webapp builder.
  286. * @see WebApps for a complete example
  287. * @param <T> application (holding the embedded webapp) type
  288. * @param prefix of the webapp
  289. * @param api the api class for the application
  290. * @param app the application instance
  291. * @param wsPrefix the prefix for the webservice api for this app
  292. * @return a webapp builder
  293. */
  294. public static <T> Builder<T> $for(String prefix, Class<T> api, T app, String wsPrefix) {
  295. return new Builder<T>(prefix, api, app, wsPrefix);
  296. }
  297. /**
  298. * Create a new webapp builder.
  299. * @see WebApps for a complete example
  300. * @param <T> application (holding the embedded webapp) type
  301. * @param prefix of the webapp
  302. * @param api the api class for the application
  303. * @param app the application instance
  304. * @return a webapp builder
  305. */
  306. public static <T> Builder<T> $for(String prefix, Class<T> api, T app) {
  307. return new Builder<T>(prefix, api, app);
  308. }
  309. // Short cut mostly for tests/demos
  310. @SuppressWarnings("unchecked")
  311. public static <T> Builder<T> $for(String prefix, T app) {
  312. return $for(prefix, (Class<T>)app.getClass(), app);
  313. }
  314. // Ditto
  315. public static <T> Builder<T> $for(T app) {
  316. return $for("", app);
  317. }
  318. public static <T> Builder<T> $for(String prefix) {
  319. return $for(prefix, null, null);
  320. }
  321. }