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            !addr.isSiteLocalAddress()) {
100          continue;
101        }
102        String hostName = addr.getHostName();
103        LOG.info("Found " + hostName + " on " + ni + ", addr=" + addr);
104
105        TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName);
106        TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName);
107        TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
108        try {
109          ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher();
110          List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode);
111          // there would be NUM_RS+1 children - one for the master
112          assertTrue(servers.size() ==
113            NUM_RS + (LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration())? 1: 0));
114          for (String server : servers) {
115            assertTrue("From zookeeper: " + server + " hostname: " + hostName,
116              server.startsWith(hostName.toLowerCase(Locale.ROOT)+","));
117          }
118          zkw.close();
119        } finally {
120          TEST_UTIL.shutdownMiniCluster();
121        }
122      }
123    }
124  }
125
126  @Test
127  public void testConflictRegionServerHostnameConfigurationsAbortServer() throws Exception {
128    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
129    while (netInterfaceList.hasMoreElements()) {
130      NetworkInterface ni = netInterfaceList.nextElement();
131      Enumeration<InetAddress> addrList = ni.getInetAddresses();
132      // iterate through host addresses and use each as hostname
133      while (addrList.hasMoreElements()) {
134        InetAddress addr = addrList.nextElement();
135        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) {
136          continue;
137        }
138        String hostName = addr.getHostName();
139        LOG.info("Found " + hostName + " on " + ni);
140
141        TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName);
142        // "hbase.regionserver.hostname" and "hbase.regionserver.hostname.disable.master.reversedns"
143        // are mutually exclusive. Exception should be thrown if both are used.
144        TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName);
145        TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true);
146        try {
147          TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
148        } catch (Exception e) {
149          Throwable t1 = e.getCause();
150          Throwable t2 = t1.getCause();
151          assertTrue(t1.getMessage()+" - "+t2.getMessage(), t2.getMessage().contains(
152            HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and " + HRegionServer.RS_HOSTNAME_KEY +
153            " are mutually exclusive"));
154          return;
155        } finally {
156          TEST_UTIL.shutdownMiniCluster();
157        }
158        assertTrue("Failed to validate against conflict hostname configurations", false);
159      }
160    }
161  }
162
163  @Test
164  public void testRegionServerHostnameReportedToMaster() throws Exception {
165    TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY,
166    true);
167    TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
168    boolean tablesOnMaster = LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration());
169    int expectedRS = NUM_RS + (tablesOnMaster? 1: 0);
170    try (ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher()) {
171      List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode);
172      assertEquals(expectedRS, servers.size());
173    }
174  }
175}