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.StartMiniClusterOption;
034import org.apache.hadoop.hbase.master.LoadBalancer;
035import org.apache.hadoop.hbase.testclassification.MediumTests;
036import org.apache.hadoop.hbase.testclassification.RegionServerTests;
037import org.apache.hadoop.hbase.zookeeper.ZKUtil;
038import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
039import org.junit.After;
040import org.junit.Before;
041import org.junit.ClassRule;
042import org.junit.Test;
043import org.junit.experimental.categories.Category;
044import org.slf4j.Logger;
045import org.slf4j.LoggerFactory;
046
047/**
048 * Tests for the hostname specification by region server
049 */
050@Category({RegionServerTests.class, MediumTests.class})
051public class TestRegionServerHostname {
052
053  @ClassRule
054  public static final HBaseClassTestRule CLASS_RULE =
055      HBaseClassTestRule.forClass(TestRegionServerHostname.class);
056
057  private static final Logger LOG = LoggerFactory.getLogger(TestRegionServerHostname.class);
058
059  private HBaseTestingUtility TEST_UTIL;
060
061  private static final int NUM_MASTERS = 1;
062  private static final int NUM_RS = 1;
063
064  @Before
065  public void setup() {
066    Configuration conf = HBaseConfiguration.create();
067    TEST_UTIL = new HBaseTestingUtility(conf);
068  }
069
070  @After
071  public void teardown() throws Exception {
072    TEST_UTIL.shutdownMiniCluster();
073  }
074
075  @Test
076  public void testInvalidRegionServerHostnameAbortsServer() throws Exception {
077    String invalidHostname = "hostAddr.invalid";
078    TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, invalidHostname);
079    HRegionServer hrs = null;
080    try {
081      hrs = new HRegionServer(TEST_UTIL.getConfiguration());
082    } catch (IllegalArgumentException iae) {
083      assertTrue(iae.getMessage(),
084        iae.getMessage().contains("Failed resolve of " + invalidHostname) ||
085        iae.getMessage().contains("Problem binding to " + invalidHostname));
086    }
087    assertNull("Failed to validate against invalid hostname", hrs);
088  }
089
090  @Test
091  public void testRegionServerHostname() throws Exception {
092    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
093    while (netInterfaceList.hasMoreElements()) {
094      NetworkInterface ni = netInterfaceList.nextElement();
095      Enumeration<InetAddress> addrList = ni.getInetAddresses();
096      // iterate through host addresses and use each as hostname
097      while (addrList.hasMoreElements()) {
098        InetAddress addr = addrList.nextElement();
099        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress() ||
100            !addr.isSiteLocalAddress()) {
101          continue;
102        }
103        String hostName = addr.getHostName();
104        LOG.info("Found " + hostName + " on " + ni + ", addr=" + addr);
105
106        TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName);
107        TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName);
108        StartMiniClusterOption option = StartMiniClusterOption.builder()
109            .numMasters(NUM_MASTERS).numRegionServers(NUM_RS).numDataNodes(NUM_RS).build();
110        TEST_UTIL.startMiniCluster(option);
111        try {
112          ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher();
113          List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode);
114          // there would be NUM_RS+1 children - one for the master
115          assertTrue(servers.size() ==
116            NUM_RS + (LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration())? 1: 0));
117          for (String server : servers) {
118            assertTrue("From zookeeper: " + server + " hostname: " + hostName,
119              server.startsWith(hostName.toLowerCase(Locale.ROOT)+","));
120          }
121          zkw.close();
122        } finally {
123          TEST_UTIL.shutdownMiniCluster();
124        }
125      }
126    }
127  }
128
129  @Test
130  public void testConflictRegionServerHostnameConfigurationsAbortServer() throws Exception {
131    Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces();
132    while (netInterfaceList.hasMoreElements()) {
133      NetworkInterface ni = netInterfaceList.nextElement();
134      Enumeration<InetAddress> addrList = ni.getInetAddresses();
135      // iterate through host addresses and use each as hostname
136      while (addrList.hasMoreElements()) {
137        InetAddress addr = addrList.nextElement();
138        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) {
139          continue;
140        }
141        String hostName = addr.getHostName();
142        LOG.info("Found " + hostName + " on " + ni);
143
144        TEST_UTIL.getConfiguration().set(HRegionServer.MASTER_HOSTNAME_KEY, hostName);
145        // "hbase.regionserver.hostname" and "hbase.regionserver.hostname.disable.master.reversedns"
146        // are mutually exclusive. Exception should be thrown if both are used.
147        TEST_UTIL.getConfiguration().set(HRegionServer.RS_HOSTNAME_KEY, hostName);
148        TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true);
149        try {
150          StartMiniClusterOption option = StartMiniClusterOption.builder()
151              .numMasters(NUM_MASTERS).numRegionServers(NUM_RS).numDataNodes(NUM_RS).build();
152          TEST_UTIL.startMiniCluster(option);
153        } catch (Exception e) {
154          Throwable t1 = e.getCause();
155          Throwable t2 = t1.getCause();
156          assertTrue(t1.getMessage()+" - "+t2.getMessage(), t2.getMessage().contains(
157            HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and " + HRegionServer.RS_HOSTNAME_KEY +
158            " are mutually exclusive"));
159          return;
160        } finally {
161          TEST_UTIL.shutdownMiniCluster();
162        }
163        assertTrue("Failed to validate against conflict hostname configurations", false);
164      }
165    }
166  }
167
168  @Test
169  public void testRegionServerHostnameReportedToMaster() throws Exception {
170    TEST_UTIL.getConfiguration().setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY,
171    true);
172    StartMiniClusterOption option = StartMiniClusterOption.builder()
173        .numMasters(NUM_MASTERS).numRegionServers(NUM_RS).numDataNodes(NUM_RS).build();
174    TEST_UTIL.startMiniCluster(option);
175    boolean tablesOnMaster = LoadBalancer.isTablesOnMaster(TEST_UTIL.getConfiguration());
176    int expectedRS = NUM_RS + (tablesOnMaster? 1: 0);
177    try (ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher()) {
178      List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode);
179      assertEquals(expectedRS, servers.size());
180    }
181  }
182}