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.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertNull; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024import static org.junit.jupiter.api.Assertions.fail; 025 026import java.net.InetAddress; 027import java.net.NetworkInterface; 028import java.util.ArrayList; 029import java.util.Enumeration; 030import java.util.List; 031import java.util.Locale; 032import org.apache.hadoop.conf.Configuration; 033import org.apache.hadoop.hbase.HBaseConfiguration; 034import org.apache.hadoop.hbase.HBaseTestingUtil; 035import org.apache.hadoop.hbase.StartTestingClusterOption; 036import org.apache.hadoop.hbase.testclassification.MediumTests; 037import org.apache.hadoop.hbase.testclassification.RegionServerTests; 038import org.apache.hadoop.hbase.util.DNS; 039import org.apache.hadoop.hbase.zookeeper.ZKUtil; 040import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 041import org.junit.jupiter.api.AfterEach; 042import org.junit.jupiter.api.BeforeEach; 043import org.junit.jupiter.api.Tag; 044import org.junit.jupiter.api.Test; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048/** 049 * Tests for the hostname specification by region server 050 */ 051@Tag(RegionServerTests.TAG) 052@Tag(MediumTests.TAG) 053public class TestRegionServerHostname { 054 055 private static final Logger LOG = LoggerFactory.getLogger(TestRegionServerHostname.class); 056 057 private HBaseTestingUtil TEST_UTIL; 058 059 private static final int NUM_MASTERS = 1; 060 private static final int NUM_RS = 1; 061 062 @BeforeEach 063 public void setup() { 064 Configuration conf = HBaseConfiguration.create(); 065 TEST_UTIL = new HBaseTestingUtil(conf); 066 } 067 068 @AfterEach 069 public void teardown() throws Exception { 070 TEST_UTIL.shutdownMiniCluster(); 071 } 072 073 @Test 074 public void testInvalidRegionServerHostnameAbortsServer() throws Exception { 075 String invalidHostname = "hostAddr.invalid"; 076 TEST_UTIL.getConfiguration().set(DNS.UNSAFE_RS_HOSTNAME_KEY, invalidHostname); 077 HRegionServer hrs = null; 078 try { 079 hrs = new HRegionServer(TEST_UTIL.getConfiguration()); 080 } catch (IllegalArgumentException iae) { 081 assertTrue(iae.getMessage().contains("Failed resolve of " + invalidHostname) 082 || iae.getMessage().contains("Problem binding to " + invalidHostname), iae.getMessage()); 083 } 084 assertNull(hrs, "Failed to validate against invalid hostname"); 085 } 086 087 @Test 088 public void testRegionServerHostname() throws Exception { 089 for (NetworkInterface ni : getValidNetworkInterfaces()) { 090 Enumeration<InetAddress> addrList = ni.getInetAddresses(); 091 // iterate through host addresses and use each as hostname 092 while (addrList.hasMoreElements()) { 093 InetAddress addr = addrList.nextElement(); 094 if ( 095 addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress() 096 || !addr.isSiteLocalAddress() 097 ) { 098 continue; 099 } 100 String hostName = addr.getHostName(); 101 LOG.info("Found " + hostName + " on " + ni + ", addr=" + addr); 102 103 TEST_UTIL.getConfiguration().set(DNS.MASTER_HOSTNAME_KEY, hostName); 104 TEST_UTIL.getConfiguration().set(DNS.UNSAFE_RS_HOSTNAME_KEY, hostName); 105 StartTestingClusterOption option = StartTestingClusterOption.builder() 106 .numMasters(NUM_MASTERS).numRegionServers(NUM_RS).numDataNodes(NUM_RS).build(); 107 TEST_UTIL.startMiniCluster(option); 108 try { 109 ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher(); 110 List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode); 111 assertEquals(NUM_RS, servers.size()); 112 for (String server : servers) { 113 assertTrue(server.startsWith(hostName.toLowerCase(Locale.ROOT) + ","), 114 "From zookeeper: " + server + " hostname: " + hostName); 115 } 116 zkw.close(); 117 } finally { 118 TEST_UTIL.shutdownMiniCluster(); 119 } 120 } 121 } 122 } 123 124 @Test 125 public void testDeprecatedConfigs() throws Exception { 126 Configuration conf = TEST_UTIL.getConfiguration(); 127 new HRegionServer(conf); 128 conf.setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, false); 129 assertFalse( 130 conf.getBoolean(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true)); 131 conf.setBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true); 132 assertTrue( 133 conf.getBoolean(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, false)); 134 conf.setBoolean(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true); 135 assertTrue(conf.getBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, false)); 136 conf.setBoolean(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, false); 137 assertFalse(conf.getBoolean(HRegionServer.RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true)); 138 139 conf.setBoolean(DNS.RS_HOSTNAME_KEY, false); 140 assertFalse(conf.getBoolean(DNS.UNSAFE_RS_HOSTNAME_KEY, true)); 141 conf.setBoolean(DNS.RS_HOSTNAME_KEY, true); 142 assertTrue(conf.getBoolean(DNS.UNSAFE_RS_HOSTNAME_KEY, false)); 143 conf.setBoolean(DNS.UNSAFE_RS_HOSTNAME_KEY, true); 144 assertTrue(conf.getBoolean(DNS.RS_HOSTNAME_KEY, false)); 145 conf.setBoolean(DNS.UNSAFE_RS_HOSTNAME_KEY, false); 146 assertFalse(conf.getBoolean(DNS.RS_HOSTNAME_KEY, true)); 147 } 148 149 @Test 150 public void testConflictRegionServerHostnameConfigurationsAbortServer() throws Exception { 151 Enumeration<NetworkInterface> netInterfaceList = NetworkInterface.getNetworkInterfaces(); 152 while (netInterfaceList.hasMoreElements()) { 153 NetworkInterface ni = netInterfaceList.nextElement(); 154 Enumeration<InetAddress> addrList = ni.getInetAddresses(); 155 // iterate through host addresses and use each as hostname 156 while (addrList.hasMoreElements()) { 157 InetAddress addr = addrList.nextElement(); 158 if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isMulticastAddress()) { 159 continue; 160 } 161 String hostName = addr.getHostName(); 162 LOG.info("Found " + hostName + " on " + ni); 163 164 TEST_UTIL.getConfiguration().set(DNS.MASTER_HOSTNAME_KEY, hostName); 165 // "hbase.unsafe.regionserver.hostname" and 166 // "hbase.unsafe.regionserver.hostname.disable.master.reversedns" 167 // are mutually exclusive. Exception should be thrown if both are used. 168 TEST_UTIL.getConfiguration().set(DNS.UNSAFE_RS_HOSTNAME_KEY, hostName); 169 TEST_UTIL.getConfiguration() 170 .setBoolean(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true); 171 try { 172 StartTestingClusterOption option = StartTestingClusterOption.builder() 173 .numMasters(NUM_MASTERS).numRegionServers(NUM_RS).numDataNodes(NUM_RS).build(); 174 TEST_UTIL.startMiniCluster(option); 175 } catch (Exception e) { 176 Throwable t1 = e.getCause(); 177 Throwable t2 = t1.getCause(); 178 assertTrue( 179 t2.getMessage() 180 .contains(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY + " and " 181 + DNS.UNSAFE_RS_HOSTNAME_KEY + " are mutually exclusive"), 182 t1.getMessage() + " - " + t2.getMessage()); 183 return; 184 } finally { 185 TEST_UTIL.shutdownMiniCluster(); 186 } 187 fail("Failed to validate against conflict hostname configurations"); 188 } 189 } 190 } 191 192 @Test 193 public void testRegionServerHostnameReportedToMaster() throws Exception { 194 TEST_UTIL.getConfiguration() 195 .setBoolean(HRegionServer.UNSAFE_RS_HOSTNAME_DISABLE_MASTER_REVERSEDNS_KEY, true); 196 StartTestingClusterOption option = StartTestingClusterOption.builder().numMasters(NUM_MASTERS) 197 .numRegionServers(NUM_RS).numDataNodes(NUM_RS).build(); 198 TEST_UTIL.startMiniCluster(option); 199 int expectedRS = NUM_RS; 200 try (ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher()) { 201 List<String> servers = ZKUtil.listChildrenNoWatch(zkw, zkw.getZNodePaths().rsZNode); 202 assertEquals(expectedRS, servers.size()); 203 } 204 } 205 206 private boolean ignoreNetworkInterface(NetworkInterface networkInterface) throws Exception { 207 return networkInterface == null || networkInterface.isLoopback() || networkInterface.isVirtual() 208 || !networkInterface.isUp(); 209 } 210 211 private List<NetworkInterface> getValidNetworkInterfaces() throws Exception { 212 List<NetworkInterface> validNetworkInterfaces = new ArrayList<>(); 213 Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); 214 while (interfaces.hasMoreElements()) { 215 NetworkInterface networkInterface = interfaces.nextElement(); 216 if (ignoreNetworkInterface(networkInterface)) { 217 continue; 218 } 219 validNetworkInterfaces.add(networkInterface); 220 } 221 return validNetworkInterfaces; 222 } 223}