View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.rest;
21  
22  import org.apache.commons.cli.CommandLine;
23  import org.apache.commons.cli.HelpFormatter;
24  import org.apache.commons.cli.Options;
25  import org.apache.commons.cli.PosixParser;
26  import org.apache.commons.cli.ParseException;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.classification.InterfaceAudience;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.HBaseConfiguration;
33  import org.apache.hadoop.hbase.rest.filter.GzipFilter;
34  import org.apache.hadoop.hbase.security.User;
35  import org.apache.hadoop.hbase.util.InfoServer;
36  import org.apache.hadoop.hbase.util.Strings;
37  import org.apache.hadoop.hbase.util.VersionInfo;
38  import org.apache.hadoop.net.DNS;
39  
40  import java.util.List;
41  import java.util.ArrayList;
42  
43  import org.mortbay.jetty.Connector;
44  import org.mortbay.jetty.Server;
45  import org.mortbay.jetty.nio.SelectChannelConnector;
46  import org.mortbay.jetty.servlet.Context;
47  import org.mortbay.jetty.servlet.ServletHolder;
48  import org.mortbay.thread.QueuedThreadPool;
49  
50  import com.sun.jersey.spi.container.servlet.ServletContainer;
51  
52  /**
53   * Main class for launching REST gateway as a servlet hosted by Jetty.
54   * <p>
55   * The following options are supported:
56   * <ul>
57   * <li>-p --port : service port</li>
58   * <li>-ro --readonly : server mode</li>
59   * </ul>
60   */
61  @InterfaceAudience.Private
62  public class RESTServer implements Constants {
63  
64    private static void printUsageAndExit(Options options, int exitCode) {
65      HelpFormatter formatter = new HelpFormatter();
66      formatter.printHelp("bin/hbase rest start", "", options,
67        "\nTo run the REST server as a daemon, execute " +
68        "bin/hbase-daemon.sh start|stop rest [--infoport <port>] [-p <port>] [-ro]\n", true);
69      System.exit(exitCode);
70    }
71  
72    /**
73     * The main method for the HBase rest server.
74     * @param args command-line arguments
75     * @throws Exception exception
76     */
77    public static void main(String[] args) throws Exception {
78      Log LOG = LogFactory.getLog("RESTServer");
79  
80      VersionInfo.logVersion();
81      Configuration conf = HBaseConfiguration.create();
82      // login the server principal (if using secure Hadoop)   
83      if (User.isSecurityEnabled() && User.isHBaseSecurityEnabled(conf)) {
84        String machineName = Strings.domainNamePointerToHostName(
85          DNS.getDefaultHost(conf.get("hbase.rest.dns.interface", "default"),
86            conf.get("hbase.rest.dns.nameserver", "default")));
87        User.login(conf, "hbase.rest.keytab.file", "hbase.rest.kerberos.principal",
88          machineName);
89      }
90      RESTServlet servlet = RESTServlet.getInstance(conf);
91  
92      Options options = new Options();
93      options.addOption("p", "port", true, "Port to bind to [default: 8080]");
94      options.addOption("ro", "readonly", false, "Respond only to GET HTTP " +
95        "method requests [default: false]");
96      options.addOption(null, "infoport", true, "Port for web UI");
97  
98      CommandLine commandLine = null;
99      try {
100       commandLine = new PosixParser().parse(options, args);
101     } catch (ParseException e) {
102       LOG.error("Could not parse: ", e);
103       printUsageAndExit(options, -1);
104     }
105 
106     // check for user-defined port setting, if so override the conf
107     if (commandLine != null && commandLine.hasOption("port")) {
108       String val = commandLine.getOptionValue("port");
109       servlet.getConfiguration()
110           .setInt("hbase.rest.port", Integer.valueOf(val));
111       LOG.debug("port set to " + val);
112     }
113 
114     // check if server should only process GET requests, if so override the conf
115     if (commandLine != null && commandLine.hasOption("readonly")) {
116       servlet.getConfiguration().setBoolean("hbase.rest.readonly", true);
117       LOG.debug("readonly set to true");
118     }
119 
120     // check for user-defined info server port setting, if so override the conf
121     if (commandLine != null && commandLine.hasOption("infoport")) {
122       String val = commandLine.getOptionValue("infoport");
123       servlet.getConfiguration()
124           .setInt("hbase.rest.info.port", Integer.valueOf(val));
125       LOG.debug("Web UI port set to " + val);
126     }
127 
128     @SuppressWarnings("unchecked")
129     List<String> remainingArgs = commandLine != null ?
130         commandLine.getArgList() : new ArrayList<String>();
131     if (remainingArgs.size() != 1) {
132       printUsageAndExit(options, 1);
133     }
134 
135     String command = remainingArgs.get(0);
136     if ("start".equals(command)) {
137       // continue and start container
138     } else if ("stop".equals(command)) {
139       System.exit(1);
140     } else {
141       printUsageAndExit(options, 1);
142     }
143 
144     // set up the Jersey servlet container for Jetty
145     ServletHolder sh = new ServletHolder(ServletContainer.class);
146     sh.setInitParameter(
147       "com.sun.jersey.config.property.resourceConfigClass",
148       ResourceConfig.class.getCanonicalName());
149     sh.setInitParameter("com.sun.jersey.config.property.packages",
150       "jetty");
151 
152     // set up Jetty and run the embedded server
153 
154     Server server = new Server();
155 
156     Connector connector = new SelectChannelConnector();
157     connector.setPort(servlet.getConfiguration().getInt("hbase.rest.port", 8080));
158     connector.setHost(servlet.getConfiguration().get("hbase.rest.host", "0.0.0.0"));
159 
160     server.addConnector(connector);
161 
162     // Set the default max thread number to 100 to limit
163     // the number of concurrent requests so that REST server doesn't OOM easily.
164     // Jetty set the default max thread number to 250, if we don't set it.
165     //
166     // Our default min thread number 2 is the same as that used by Jetty.
167     int maxThreads = servlet.getConfiguration().getInt("hbase.rest.threads.max", 100);
168     int minThreads = servlet.getConfiguration().getInt("hbase.rest.threads.min", 2);
169     QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads);
170     threadPool.setMinThreads(minThreads);
171     server.setThreadPool(threadPool);
172 
173     server.setSendServerVersion(false);
174     server.setSendDateHeader(false);
175     server.setStopAtShutdown(true);
176       // set up context
177     Context context = new Context(server, "/", Context.SESSIONS);
178     context.addServlet(sh, "/*");
179     context.addFilter(GzipFilter.class, "/*", 0);
180 
181     // Put up info server.
182     int port = conf.getInt("hbase.rest.info.port", 8085);
183     if (port >= 0) {
184       conf.setLong("startcode", System.currentTimeMillis());
185       String a = conf.get("hbase.rest.info.bindAddress", "0.0.0.0");
186       InfoServer infoServer = new InfoServer("rest", a, port, false, conf);
187       infoServer.setAttribute("hbase.conf", conf);
188       infoServer.start();
189     }
190 
191     // start server
192     server.start();
193     server.join();
194   }
195 }