diff --git a/hbase-common/src/main/resources/hbase-default.xml b/hbase-common/src/main/resources/hbase-default.xml index 70c638b9134..0ea9cc759bc 100644 --- a/hbase-common/src/main/resources/hbase-default.xml +++ b/hbase-common/src/main/resources/hbase-default.xml @@ -988,6 +988,15 @@ possible configurations would overwhelm and obscure the important. When set to a non-empty value, this represents the (external facing) hostname for the underlying server. See https://issues.apache.org/jira/browse/HBASE-12954 for details. + + hbase.regionserver.hostname.disable.master.reversedns + false + This config is for experts: don't set its value unless you really know what you are doing. + When set to true, regionserver will use the current node hostname for the servername and HMaster will + skip reverse DNS lookup and use the hostname sent by regionserver instead. Note that this config and + hbase.regionserver.hostname are mutually exclusive. See https://issues.apache.org/jira/browse/HBASE-18226 + for more details. + diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 61e89333d7a..f0537e0f15b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -450,6 +450,11 @@ public class HRegionServer extends HasThread implements @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) protected final static String MASTER_HOSTNAME_KEY = "hbase.master.hostname"; + // HBASE-18226: This config and hbase.regionserver.hostname are mutually exclusive. + // Exception will be thrown if both are used. + final static String RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY = + "hbase.regionserver.hostname.disable.master.reversedns"; + /** * This servers startcode. */ @@ -577,6 +582,16 @@ public class HRegionServer extends HasThread implements useThisHostnameInstead = conf.get(MASTER_HOSTNAME_KEY); } else { useThisHostnameInstead = conf.get(RS_HOSTNAME_KEY); + if (conf.getBoolean(RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, false)) { + if (shouldUseThisHostnameInstead()) { + String msg = RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and " + RS_HOSTNAME_KEY + + " are mutually exclusive. Do not set " + RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + + " to true while " + RS_HOSTNAME_KEY + " is used"; + throw new IOException(msg); + } else { + useThisHostnameInstead = rpcServices.isa.getHostName(); + } + } } String hostName = shouldUseThisHostnameInstead() ? useThisHostnameInstead : rpcServices.isa.getHostName(); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java index 63e33d4819f..679595ae6ef 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestRegionServerHostname.java @@ -28,6 +28,8 @@ import java.util.Locale; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.RegionServerTests; @@ -42,13 +44,14 @@ import org.junit.experimental.categories.Category; @Category({RegionServerTests.class, MediumTests.class}) public class TestRegionServerHostname { private static final Log LOG = LogFactory.getLog(TestRegionServerHostname.class); - private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); @Test (timeout=30000) public void testInvalidRegionServerHostnameAbortsServer() throws Exception { final int NUM_MASTERS = 1; final int NUM_RS = 1; String invalidHostname = "hostAddr.invalid"; + Configuration conf = HBaseConfiguration.create(); + HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(conf); TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, invalidHostname); try { TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS); @@ -70,7 +73,8 @@ public class TestRegionServerHostname { final int NUM_MASTERS = 1; final int NUM_RS = 1; Enumeration netInterfaceList = NetworkInterface.getNetworkInterfaces(); - + Configuration conf = HBaseConfiguration.create(); + HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(conf); while (netInterfaceList.hasMoreElements()) { NetworkInterface ni = netInterfaceList.nextElement(); Enumeration addrList = ni.getInetAddresses(); @@ -82,7 +86,7 @@ public class TestRegionServerHostname { } String hostName = addr.getHostName(); LOG.info("Found " + hostName + " on " + ni); - + TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName); TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName); TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS); @@ -102,4 +106,64 @@ public class TestRegionServerHostname { } } } + + @Test(timeout=30000) + public void testConflictRegionServerHostnameConfigurationsAbortServer() throws Exception { + final int NUM_MASTERS = 1; + final int NUM_RS = 1; + Enumeration netInterfaceList = NetworkInterface.getNetworkInterfaces(); + Configuration conf = HBaseConfiguration.create(); + HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(conf); + while (netInterfaceList.hasMoreElements()) { + NetworkInterface ni = netInterfaceList.nextElement(); + Enumeration addrList = ni.getInetAddresses(); + // iterate through host addresses and use each as hostname + while (addrList.hasMoreElements()) { + InetAddress addr = addrList.nextElement(); + if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) { + continue; + } + String hostName = addr.getHostName(); + LOG.info("Found " + hostName + " on " + ni); + + TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName); + // "hbase.regionserver.hostname" and "hbase.regionserver.hostname.disable.master.reversedns" + // are mutually exclusive. Exception should be thrown if both are used. + TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName); + TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true); + try { + TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS); + } catch (Exception e) { + Throwable t1 = e.getCause(); + Throwable t2 = t1.getCause(); + assertTrue(t1.getMessage()+" - "+t2.getMessage(), t2.getMessage().contains( + HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and " + HRegionServer.RS_HOSTNAME_KEY + + " are mutually exclusive")); + return; + } finally { + TEST_UTIL.shutdownMiniCluster(); + } + assertTrue("Failed to validate against conflict hostname configurations", false); + } + } + } + + @Test(timeout=30000) + public void testRegionServerHostnameReportedToMaster() throws Exception { + final int NUM_MASTERS = 1; + final int NUM_RS = 1; + Configuration conf = HBaseConfiguration.create(); + HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(conf); + TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true); + TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS); + try { + ZooKeeperWatcher zkw = TEST_UTIL.getZooKeeperWatcher(); + List servers = ZKUtil.listChildrenNoWatch(zkw, zkw.znodePaths.rsZNode); + // there would be NUM_RS+1 children - one for the master + assertTrue(servers.size() == NUM_RS+1); + zkw.close(); + } finally { + TEST_UTIL.shutdownMiniCluster(); + } + } }