001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNull;
022import static org.junit.Assert.assertTrue;
023
024import java.net.InetAddress;
025import java.net.NetworkInterface;
026import java.util.Enumeration;
027import java.util.List;
028import java.util.Locale;
029import org.apache.hadoop.conf.Configuration;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.HBaseConfiguration;
032import org.apache.hadoop.hbase.HBaseTestingUtility;
033import org.apache.hadoop.hbase.master.LoadBalancer;
034import org.apache.hadoop.hbase.testclassification.MediumTests;
035import org.apache.hadoop.hbase.testclassification.RegionServerTests;
036import org.apache.hadoop.hbase.zookeeper.ZKUtil;
037import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
038import org.junit.After;
039import org.junit.Before;
040import org.junit.ClassRule;
041import org.junit.Test;
042import org.junit.experimental.categories.Category;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045
046/**
047 * Tests for the hostname specification by region server
048 */
049@Category({RegionServerTests.class, MediumTests.class})
050public class TestRegionServerHostname {
051
052  @ClassRule
053  public static final HBaseClassTestRule CLASS_RULE =
054      HBaseClassTestRule.forClass(TestRegionServerHostname.class);
055
056  private static final Logger LOG = LoggerFactory.getLogger(TestRegionServerHostname.class);
057
058  private HBaseTestingUtility TEST_UTIL;
059
060  private static final int NUM_MASTERS = 1;
061  private static final int NUM_RS = 1;
062
063  @Before
064  public void setup() {
065    Configuration conf = HBaseConfiguration.create();
066    TEST_UTIL = new HBaseTestingUtility(conf);
067  }
068
069  @After
070  public void teardown() throws Exception {
071    TEST_UTIL.shutdownMiniCluster();
072  }
073
074  @Test
075  public void testInvalidRegionServerHostnameAbortsServer() throws Exception {
076    String invalidHostname = "hostAddr.invalid";
077    TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, invalidHostname);
078    HRegionServer hrs = null;
079    try {
080      hrs = new HRegionServer(TEST_UTIL.getConfiguration());
081    } catch (IllegalArgumentException iae) {
082      assertTrue(iae.getMessage(),
083        iae.getMessage().contains("Failed resolve of " + invalidHostname) ||
084        iae.getMessage().contains("Problem binding to " + invalidHostname));
085    }
086    assertNull("Failed to validate against invalid hostname", hrs);
087  }
088
089  @Test
090  public void testRegionServerHostname() throws Exception {
091    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
092    while (netInterfaceList.hasMoreElements()) {
093      NetworkInterface ni = netInterfaceList.nextElement();
094      Enumeration<InetAddress> addrList = ni.getInetAddresses();
095      // iterate through host addresses and use each as hostname
096      while (addrList.hasMoreElements()) {
097        InetAddress addr = addrList.nextElement();
098        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) {
099          continue;
100        }
101        String hostName = addr.getHostName();
102        LOG.info("Found " + hostName + " on " + ni);
103
104        TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName);
105        TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName);
106        TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
107        try {
108          ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher();
109          List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode);
110          // there would be NUM_RS+1 children - one for the master
111          assertTrue(servers.size() ==
112            NUM_RS + (LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration())? 1: 0));
113          for (String server : servers) {
114            assertTrue("From zookeeper: " + server + " hostname: " + hostName,
115              server.startsWith(hostName.toLowerCase(Locale.ROOT)+","));
116          }
117          zkw.close();
118        } finally {
119          TEST_UTIL.shutdownMiniCluster();
120        }
121      }
122    }
123  }
124
125  @Test
126  public void testConflictRegionServerHostnameConfigurationsAbortServer() throws Exception {
127    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
128    while (netInterfaceList.hasMoreElements()) {
129      NetworkInterface ni = netInterfaceList.nextElement();
130      Enumeration<InetAddress> addrList = ni.getInetAddresses();
131      // iterate through host addresses and use each as hostname
132      while (addrList.hasMoreElements()) {
133        InetAddress addr = addrList.nextElement();
134        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) {
135          continue;
136        }
137        String hostName = addr.getHostName();
138        LOG.info("Found " + hostName + " on " + ni);
139
140        TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName);
141        // "hbase.regionserver.hostname" and "hbase.regionserver.hostname.disable.master.reversedns"
142        // are mutually exclusive. Exception should be thrown if both are used.
143        TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName);
144        TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true);
145        try {
146          TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
147        } catch (Exception e) {
148          Throwable t1 = e.getCause();
149          Throwable t2 = t1.getCause();
150          assertTrue(t1.getMessage()+" - "+t2.getMessage(), t2.getMessage().contains(
151            HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and " + HRegionServer.RS_HOSTNAME_KEY +
152            " are mutually exclusive"));
153          return;
154        } finally {
155          TEST_UTIL.shutdownMiniCluster();
156        }
157        assertTrue("Failed to validate against conflict hostname configurations", false);
158      }
159    }
160  }
161
162  @Test
163  public void testRegionServerHostnameReportedToMaster() throws Exception {
164    TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY,
165    true);
166    TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
167    boolean tablesOnMaster = LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration());
168    int expectedRS = NUM_RS + (tablesOnMaster? 1: 0);
169    try (ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher()) {
170      List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode);
171      assertEquals(expectedRS, servers.size());
172    }
173  }
174}