HBASE-15328 sanity check the redirect used to send master info requests to the embedded regionserver.
Signed-off-by: Esteban Gutierrez <esteban@apache.org>
This commit is contained in:
parent
45357c078d
commit
cdb38830d7
|
@ -86,6 +86,7 @@ import org.apache.hadoop.hbase.client.Result;
|
||||||
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
|
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
|
||||||
import org.apache.hadoop.hbase.exceptions.DeserializationException;
|
import org.apache.hadoop.hbase.exceptions.DeserializationException;
|
||||||
import org.apache.hadoop.hbase.executor.ExecutorType;
|
import org.apache.hadoop.hbase.executor.ExecutorType;
|
||||||
|
import org.apache.hadoop.hbase.http.InfoServer;
|
||||||
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
|
import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
|
||||||
import org.apache.hadoop.hbase.ipc.RpcServer;
|
import org.apache.hadoop.hbase.ipc.RpcServer;
|
||||||
import org.apache.hadoop.hbase.ipc.ServerNotRunningYetException;
|
import org.apache.hadoop.hbase.ipc.ServerNotRunningYetException;
|
||||||
|
@ -177,6 +178,7 @@ import org.apache.zookeeper.KeeperException;
|
||||||
import org.mortbay.jetty.Connector;
|
import org.mortbay.jetty.Connector;
|
||||||
import org.mortbay.jetty.nio.SelectChannelConnector;
|
import org.mortbay.jetty.nio.SelectChannelConnector;
|
||||||
import org.mortbay.jetty.servlet.Context;
|
import org.mortbay.jetty.servlet.Context;
|
||||||
|
import org.mortbay.jetty.servlet.ServletHolder;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
@ -203,7 +205,6 @@ import com.google.protobuf.Service;
|
||||||
public class HMaster extends HRegionServer implements MasterServices, Server {
|
public class HMaster extends HRegionServer implements MasterServices, Server {
|
||||||
private static final Log LOG = LogFactory.getLog(HMaster.class.getName());
|
private static final Log LOG = LogFactory.getLog(HMaster.class.getName());
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protection against zombie master. Started once Master accepts active responsibility and
|
* Protection against zombie master. Started once Master accepts active responsibility and
|
||||||
* starts taking over responsibilities. Allows a finite time window before giving up ownership.
|
* starts taking over responsibilities. Allows a finite time window before giving up ownership.
|
||||||
|
@ -368,14 +369,42 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
|
||||||
private org.mortbay.jetty.Server masterJettyServer;
|
private org.mortbay.jetty.Server masterJettyServer;
|
||||||
|
|
||||||
public static class RedirectServlet extends HttpServlet {
|
public static class RedirectServlet extends HttpServlet {
|
||||||
private static final long serialVersionUID = 2894774810058302472L;
|
private static final long serialVersionUID = 2894774810058302473L;
|
||||||
private static int regionServerInfoPort;
|
private final int regionServerInfoPort;
|
||||||
|
private final String regionServerHostname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param infoServer that we're trying to send all requests to
|
||||||
|
* @param hostname may be null. if given, will be used for redirects instead of host from client.
|
||||||
|
*/
|
||||||
|
public RedirectServlet(InfoServer infoServer, String hostname) {
|
||||||
|
regionServerInfoPort = infoServer.getPort();
|
||||||
|
regionServerHostname = hostname;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request,
|
public void doGet(HttpServletRequest request,
|
||||||
HttpServletResponse response) throws ServletException, IOException {
|
HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
String redirectHost = regionServerHostname;
|
||||||
|
if(redirectHost == null) {
|
||||||
|
redirectHost = request.getServerName();
|
||||||
|
if(!Addressing.isLocalAddress(InetAddress.getByName(redirectHost))) {
|
||||||
|
LOG.warn("Couldn't resolve '" + redirectHost + "' as an address local to this node and '" +
|
||||||
|
MASTER_HOSTNAME_KEY + "' is not set; client will get a HTTP 400 response. If " +
|
||||||
|
"your HBase deployment relies on client accessible names that the region server process " +
|
||||||
|
"can't resolve locally, then you should set the previously mentioned configuration variable " +
|
||||||
|
"to an appropriate hostname.");
|
||||||
|
// no sending client provided input back to the client, so the goal host is just in the logs.
|
||||||
|
response.sendError(400, "Request was to a host that I can't resolve for any of the network interfaces on " +
|
||||||
|
"this node. If this is due to an intermediary such as an HTTP load balancer or other proxy, your HBase " +
|
||||||
|
"administrator can set '" + MASTER_HOSTNAME_KEY + "' to point to the correct hostname.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO this scheme should come from looking at the scheme registered in the infoserver's http server for the
|
||||||
|
// host and port we're using, but it's buried way too deep to do that ATM.
|
||||||
String redirectUrl = request.getScheme() + "://"
|
String redirectUrl = request.getScheme() + "://"
|
||||||
+ request.getServerName() + ":" + regionServerInfoPort
|
+ redirectHost + ":" + regionServerInfoPort
|
||||||
+ request.getRequestURI();
|
+ request.getRequestURI();
|
||||||
response.sendRedirect(redirectUrl);
|
response.sendRedirect(redirectUrl);
|
||||||
}
|
}
|
||||||
|
@ -481,13 +510,16 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
|
||||||
if (!conf.getBoolean("hbase.master.infoserver.redirect", true)) {
|
if (!conf.getBoolean("hbase.master.infoserver.redirect", true)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int infoPort = conf.getInt("hbase.master.info.port.orig",
|
final int infoPort = conf.getInt("hbase.master.info.port.orig",
|
||||||
HConstants.DEFAULT_MASTER_INFOPORT);
|
HConstants.DEFAULT_MASTER_INFOPORT);
|
||||||
// -1 is for disabling info server, so no redirecting
|
// -1 is for disabling info server, so no redirecting
|
||||||
if (infoPort < 0 || infoServer == null) {
|
if (infoPort < 0 || infoServer == null) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
String addr = conf.get("hbase.master.info.bindAddress", "0.0.0.0");
|
if(infoPort == infoServer.getPort()) {
|
||||||
|
return infoPort;
|
||||||
|
}
|
||||||
|
final String addr = conf.get("hbase.master.info.bindAddress", "0.0.0.0");
|
||||||
if (!Addressing.isLocalAddress(InetAddress.getByName(addr))) {
|
if (!Addressing.isLocalAddress(InetAddress.getByName(addr))) {
|
||||||
String msg =
|
String msg =
|
||||||
"Failed to start redirecting jetty server. Address " + addr
|
"Failed to start redirecting jetty server. Address " + addr
|
||||||
|
@ -497,18 +529,22 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
|
||||||
throw new IOException(msg);
|
throw new IOException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedirectServlet.regionServerInfoPort = infoServer.getPort();
|
// TODO I'm pretty sure we could just add another binding to the InfoServer run by
|
||||||
if(RedirectServlet.regionServerInfoPort == infoPort) {
|
// the RegionServer and have it run the RedirectServlet instead of standing up
|
||||||
return infoPort;
|
// a second entire stack here.
|
||||||
}
|
|
||||||
masterJettyServer = new org.mortbay.jetty.Server();
|
masterJettyServer = new org.mortbay.jetty.Server();
|
||||||
Connector connector = new SelectChannelConnector();
|
Connector connector = new SelectChannelConnector();
|
||||||
connector.setHost(addr);
|
connector.setHost(addr);
|
||||||
connector.setPort(infoPort);
|
connector.setPort(infoPort);
|
||||||
masterJettyServer.addConnector(connector);
|
masterJettyServer.addConnector(connector);
|
||||||
masterJettyServer.setStopAtShutdown(true);
|
masterJettyServer.setStopAtShutdown(true);
|
||||||
|
|
||||||
|
final String redirectHostname = shouldUseThisHostnameInstead() ? useThisHostnameInstead : null;
|
||||||
|
|
||||||
|
final RedirectServlet redirect = new RedirectServlet(infoServer, redirectHostname);
|
||||||
Context context = new Context(masterJettyServer, "/", Context.NO_SESSIONS);
|
Context context = new Context(masterJettyServer, "/", Context.NO_SESSIONS);
|
||||||
context.addServlet(RedirectServlet.class, "/*");
|
context.addServlet(new ServletHolder(redirect), "/*");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
masterJettyServer.start();
|
masterJettyServer.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -420,14 +420,15 @@ public class HRegionServer extends HasThread implements
|
||||||
/*
|
/*
|
||||||
* hostname specified by hostname config
|
* hostname specified by hostname config
|
||||||
*/
|
*/
|
||||||
private String useThisHostnameInstead;
|
protected String useThisHostnameInstead;
|
||||||
|
|
||||||
// key to the config parameter of server hostname
|
// key to the config parameter of server hostname
|
||||||
// the specification of server hostname is optional. The hostname should be resolvable from
|
// the specification of server hostname is optional. The hostname should be resolvable from
|
||||||
// both master and region server
|
// both master and region server
|
||||||
|
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
|
||||||
final static String RS_HOSTNAME_KEY = "hbase.regionserver.hostname";
|
final static String RS_HOSTNAME_KEY = "hbase.regionserver.hostname";
|
||||||
|
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
|
||||||
final static String MASTER_HOSTNAME_KEY = "hbase.master.hostname";
|
protected final static String MASTER_HOSTNAME_KEY = "hbase.master.hostname";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This servers startcode.
|
* This servers startcode.
|
||||||
|
|
|
@ -65,7 +65,8 @@ public class TestInfoServers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* Ensure when we go to top level index pages that we get redirected to an info-server specific status
|
||||||
|
* page.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testInfoServersRedirect() throws Exception {
|
public void testInfoServersRedirect() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue