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.master.assignment; 019 020import static org.hamcrest.MatcherAssert.assertThat; 021import static org.hamcrest.core.Is.isA; 022import static org.junit.jupiter.api.Assertions.assertEquals; 023import static org.junit.jupiter.api.Assertions.assertNotNull; 024import static org.junit.jupiter.api.Assertions.assertThrows; 025 026import java.io.IOException; 027import java.util.List; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.hbase.HBaseTestingUtil; 030import org.apache.hadoop.hbase.ServerName; 031import org.apache.hadoop.hbase.SingleProcessHBaseCluster; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.YouAreDeadException; 034import org.apache.hadoop.hbase.client.Admin; 035import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 036import org.apache.hadoop.hbase.client.RegionInfo; 037import org.apache.hadoop.hbase.client.TableDescriptor; 038import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 039import org.apache.hadoop.hbase.master.HMaster; 040import org.apache.hadoop.hbase.master.procedure.MasterProcedureConstants; 041import org.apache.hadoop.hbase.testclassification.MasterTests; 042import org.apache.hadoop.hbase.testclassification.MediumTests; 043import org.apache.hadoop.hbase.util.Bytes; 044import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 045import org.junit.jupiter.api.AfterAll; 046import org.junit.jupiter.api.AfterEach; 047import org.junit.jupiter.api.BeforeAll; 048import org.junit.jupiter.api.BeforeEach; 049import org.junit.jupiter.api.Disabled; 050import org.junit.jupiter.api.Tag; 051import org.junit.jupiter.api.Test; 052import org.junit.jupiter.api.TestInfo; 053import org.slf4j.Logger; 054import org.slf4j.LoggerFactory; 055 056import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; 057import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 058 059import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 060import org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos; 061import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 062import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos; 063 064/** 065 * Tests to verify master/ assignment manager functionality against rogue RS 066 */ 067@Tag(MasterTests.TAG) 068@Tag(MediumTests.TAG) 069public class TestRogueRSAssignment { 070 071 private static final Logger LOG = LoggerFactory.getLogger(TestRogueRSAssignment.class); 072 private String testMethodName; 073 074 @BeforeEach 075 public void setTestMethod(TestInfo testInfo) { 076 testMethodName = testInfo.getTestMethod().get().getName(); 077 } 078 079 private static final int initialRegionCount = 3; 080 private final static byte[] FAMILY = Bytes.toBytes("FAMILY"); 081 082 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 083 private static final Configuration conf = UTIL.getConfiguration(); 084 private static Admin admin; 085 private static SingleProcessHBaseCluster cluster; 086 private static HMaster master; 087 088 private static void setupConf(Configuration conf) { 089 // Reduce the maximum attempts to speed up the test 090 conf.setInt("hbase.assignment.maximum.attempts", 3); 091 conf.setInt("hbase.master.maximum.ping.server.attempts", 3); 092 conf.setInt("hbase.master.ping.server.retry.sleep.interval", 1); 093 conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); 094 } 095 096 @BeforeAll 097 public static void setupCluster() throws Exception { 098 setupConf(conf); 099 UTIL.startMiniCluster(2); 100 101 cluster = UTIL.getHBaseCluster(); 102 assertNotNull(cluster); 103 104 admin = UTIL.getAdmin(); 105 assertNotNull(admin); 106 107 master = cluster.getMaster(); 108 assertNotNull(master); 109 } 110 111 @AfterAll 112 public static void cleanupTest() throws Exception { 113 try { 114 UTIL.shutdownMiniCluster(); 115 cluster = null; 116 admin = null; 117 } catch (Exception e) { 118 LOG.warn("failure shutting down cluster", e); 119 } 120 } 121 122 @BeforeEach 123 public void setup() throws IOException { 124 // Turn off balancer 125 admin.balancerSwitch(false, true); 126 } 127 128 @AfterEach 129 public void tearDown() throws Exception { 130 for (TableDescriptor td : UTIL.getAdmin().listTableDescriptors()) { 131 LOG.info("Tear down, remove table=" + td.getTableName()); 132 UTIL.deleteTable(td.getTableName()); 133 } 134 // Turn on balancer 135 admin.balancerSwitch(true, false); 136 } 137 138 /** 139 * Ignore this test, see HBASE-21421 140 */ 141 @Test 142 @Disabled 143 public void testReportRSWithWrongRegion() throws Exception { 144 final TableName tableName = TableName.valueOf(testMethodName); 145 146 List<RegionInfo> tableRegions = createTable(tableName); 147 148 final ServerName sn = ServerName.parseVersionedServerName(ServerName 149 .valueOf("1.example.org", 1, EnvironmentEdgeManager.currentTime()).getVersionedBytes()); 150 151 // make fake request with a region assigned to different RS 152 RegionServerStatusProtos.RegionServerReportRequest.Builder request = 153 makeRSReportRequestWithRegions(sn, tableRegions.get(1)); 154 155 // sending fake request to master 156 // TODO: replace YouAreDeadException with appropriate exception as and when necessary 157 ServiceException exception = assertThrows(ServiceException.class, 158 () -> master.getMasterRpcServices().regionServerReport(null, request.build())); 159 assertThat((YouAreDeadException) exception.getCause(), isA(YouAreDeadException.class)); 160 } 161 162 private RegionServerStatusProtos.RegionServerReportRequest.Builder 163 makeRSReportRequestWithRegions(final ServerName sn, RegionInfo... regions) { 164 ClusterStatusProtos.ServerLoad.Builder sl = ClusterStatusProtos.ServerLoad.newBuilder(); 165 for (int i = 0; i < regions.length; i++) { 166 HBaseProtos.RegionSpecifier.Builder rs = HBaseProtos.RegionSpecifier.newBuilder(); 167 rs.setType(HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME); 168 rs.setValue(UnsafeByteOperations.unsafeWrap(regions[i].getRegionName())); 169 170 ClusterStatusProtos.RegionLoad.Builder rl = 171 ClusterStatusProtos.RegionLoad.newBuilder().setRegionSpecifier(rs.build()); 172 173 sl.addRegionLoads(i, rl.build()); 174 } 175 176 return RegionServerStatusProtos.RegionServerReportRequest.newBuilder() 177 .setServer(ProtobufUtil.toServerName(sn)).setLoad(sl); 178 } 179 180 private List<RegionInfo> createTable(final TableName tableName) throws Exception { 181 TableDescriptorBuilder tdBuilder = TableDescriptorBuilder.newBuilder(tableName); 182 tdBuilder.setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILY).build()); 183 184 byte[][] rows = new byte[initialRegionCount - 1][]; 185 for (int i = 0; i < rows.length; ++i) { 186 rows[i] = Bytes.toBytes(String.format("%d", i)); 187 } 188 admin.createTable(tdBuilder.build(), rows); 189 return assertRegionCount(tableName, initialRegionCount); 190 } 191 192 private List<RegionInfo> assertRegionCount(final TableName tableName, final int nregions) 193 throws Exception { 194 UTIL.waitUntilNoRegionsInTransition(); 195 List<RegionInfo> tableRegions = admin.getRegions(tableName); 196 assertEquals(nregions, tableRegions.size()); 197 return tableRegions; 198 } 199}