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; 019 020import java.io.IOException; 021import java.util.EnumSet; 022import java.util.List; 023import java.util.Optional; 024import java.util.concurrent.atomic.AtomicInteger; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.ClusterMetrics.Option; 027import org.apache.hadoop.hbase.Waiter.Predicate; 028import org.apache.hadoop.hbase.client.Admin; 029import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 030import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor; 031import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; 032import org.apache.hadoop.hbase.coprocessor.MasterObserver; 033import org.apache.hadoop.hbase.coprocessor.ObserverContext; 034import org.apache.hadoop.hbase.master.HMaster; 035import org.apache.hadoop.hbase.regionserver.HRegionServer; 036import org.apache.hadoop.hbase.testclassification.MediumTests; 037import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread; 038import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 039import org.junit.AfterClass; 040import org.junit.Assert; 041import org.junit.BeforeClass; 042import org.junit.ClassRule; 043import org.junit.Test; 044import org.junit.experimental.categories.Category; 045 046/** 047 * Test the ClusterStatus. 048 */ 049@Category(MediumTests.class) 050public class TestClientClusterStatus { 051 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestClientClusterStatus.class); 055 056 private static HBaseTestingUtil UTIL; 057 private static Admin ADMIN; 058 private final static int SLAVES = 5; 059 private final static int MASTERS = 3; 060 private static SingleProcessHBaseCluster CLUSTER; 061 private static HRegionServer DEAD; 062 063 @BeforeClass 064 public static void setUpBeforeClass() throws Exception { 065 Configuration conf = HBaseConfiguration.create(); 066 conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, MyObserver.class.getName()); 067 UTIL = new HBaseTestingUtil(conf); 068 StartTestingClusterOption option = StartTestingClusterOption.builder().numMasters(MASTERS) 069 .numRegionServers(SLAVES).numDataNodes(SLAVES).build(); 070 UTIL.startMiniCluster(option); 071 CLUSTER = UTIL.getHBaseCluster(); 072 CLUSTER.waitForActiveAndReadyMaster(); 073 ADMIN = UTIL.getAdmin(); 074 // Kill one region server 075 List<RegionServerThread> rsts = CLUSTER.getLiveRegionServerThreads(); 076 RegionServerThread rst = rsts.get(rsts.size() - 1); 077 DEAD = rst.getRegionServer(); 078 DEAD.stop("Test dead servers status"); 079 while (rst.isAlive()) { 080 Thread.sleep(500); 081 } 082 } 083 084 @Test 085 public void testNone() throws Exception { 086 ClusterMetrics status0 = ADMIN.getClusterMetrics(EnumSet.allOf(Option.class)); 087 ClusterMetrics status1 = ADMIN.getClusterMetrics(EnumSet.noneOf(Option.class)); 088 // Do a rough compare. More specific compares can fail because all regions not deployed yet 089 // or more requests than expected. 090 Assert.assertEquals(status0.getLiveServerMetrics().size(), 091 status1.getLiveServerMetrics().size()); 092 } 093 094 @Test 095 public void testLiveAndDeadServersStatus() throws Exception { 096 // Count the number of live regionservers 097 List<RegionServerThread> regionserverThreads = CLUSTER.getLiveRegionServerThreads(); 098 int numRs = 0; 099 int len = regionserverThreads.size(); 100 for (int i = 0; i < len; i++) { 101 if (regionserverThreads.get(i).isAlive()) { 102 numRs++; 103 } 104 } 105 // Depending on the (random) order of unit execution we may run this unit before the 106 // minicluster is fully up and recovered from the RS shutdown done during test init. 107 Waiter.waitFor(CLUSTER.getConfiguration(), 10 * 1000, 100, new Predicate<Exception>() { 108 @Override 109 public boolean evaluate() throws Exception { 110 ClusterMetrics status = ADMIN.getClusterMetrics(EnumSet.of(Option.LIVE_SERVERS)); 111 Assert.assertNotNull(status); 112 return status.getRegionCount() > 0; 113 } 114 }); 115 // Retrieve live servers and dead servers info. 116 EnumSet<Option> options = 117 EnumSet.of(Option.LIVE_SERVERS, Option.DEAD_SERVERS, Option.SERVERS_NAME); 118 ClusterMetrics status = ADMIN.getClusterMetrics(options); 119 Assert.assertNotNull(status); 120 Assert.assertNotNull(status.getLiveServerMetrics().keySet()); 121 // exclude a dead region server 122 Assert.assertEquals(SLAVES - 1, numRs); 123 // live servers = nums of regionservers 124 // By default, HMaster don't carry any regions so it won't report its load. 125 // Hence, it won't be in the server list. 126 Assert.assertEquals(status.getLiveServerMetrics().keySet().size(), numRs); 127 Assert.assertTrue(status.getRegionCount() > 0); 128 Assert.assertNotNull(status.getDeadServerNames()); 129 Assert.assertEquals(1, status.getDeadServerNames().size()); 130 ServerName deadServerName = status.getDeadServerNames().iterator().next(); 131 Assert.assertEquals(DEAD.getServerName(), deadServerName); 132 Assert.assertNotNull(status.getServersName()); 133 Assert.assertEquals(numRs, status.getServersName().size()); 134 } 135 136 @Test 137 public void testMasterAndBackupMastersStatus() throws Exception { 138 // get all the master threads 139 List<MasterThread> masterThreads = CLUSTER.getMasterThreads(); 140 int numActive = 0; 141 int activeIndex = 0; 142 ServerName activeName = null; 143 HMaster active = null; 144 for (int i = 0; i < masterThreads.size(); i++) { 145 if (masterThreads.get(i).getMaster().isActiveMaster()) { 146 numActive++; 147 activeIndex = i; 148 active = masterThreads.get(activeIndex).getMaster(); 149 activeName = active.getServerName(); 150 } 151 } 152 Assert.assertNotNull(active); 153 Assert.assertEquals(1, numActive); 154 Assert.assertEquals(MASTERS, masterThreads.size()); 155 // Retrieve master and backup masters infos only. 156 EnumSet<Option> options = EnumSet.of(Option.MASTER, Option.BACKUP_MASTERS); 157 ClusterMetrics status = ADMIN.getClusterMetrics(options); 158 Assert.assertTrue(status.getMasterName().equals(activeName)); 159 Assert.assertEquals(MASTERS - 1, status.getBackupMasterNames().size()); 160 } 161 162 @Test 163 public void testOtherStatusInfos() throws Exception { 164 EnumSet<Option> options = EnumSet.of(Option.MASTER_COPROCESSORS, Option.HBASE_VERSION, 165 Option.CLUSTER_ID, Option.BALANCER_ON); 166 ClusterMetrics status = ADMIN.getClusterMetrics(options); 167 Assert.assertTrue(status.getMasterCoprocessorNames().size() == 1); 168 Assert.assertNotNull(status.getHBaseVersion()); 169 Assert.assertNotNull(status.getClusterId()); 170 Assert.assertTrue(status.getAverageLoad() == 0.0); 171 Assert.assertNotNull(status.getBalancerOn()); 172 } 173 174 @AfterClass 175 public static void tearDownAfterClass() throws Exception { 176 if (ADMIN != null) ADMIN.close(); 177 UTIL.shutdownMiniCluster(); 178 } 179 180 @Test 181 public void testObserver() throws IOException { 182 int preCount = MyObserver.PRE_COUNT.get(); 183 int postCount = MyObserver.POST_COUNT.get(); 184 Assert.assertTrue(ADMIN.getClusterMetrics().getMasterCoprocessorNames().stream() 185 .anyMatch(s -> s.equals(MyObserver.class.getSimpleName()))); 186 Assert.assertEquals(preCount + 1, MyObserver.PRE_COUNT.get()); 187 Assert.assertEquals(postCount + 1, MyObserver.POST_COUNT.get()); 188 } 189 190 public static class MyObserver implements MasterCoprocessor, MasterObserver { 191 private static final AtomicInteger PRE_COUNT = new AtomicInteger(0); 192 private static final AtomicInteger POST_COUNT = new AtomicInteger(0); 193 194 @Override 195 public Optional<MasterObserver> getMasterObserver() { 196 return Optional.of(this); 197 } 198 199 @Override 200 public void preGetClusterMetrics(ObserverContext<MasterCoprocessorEnvironment> ctx) 201 throws IOException { 202 PRE_COUNT.incrementAndGet(); 203 } 204 205 @Override 206 public void postGetClusterMetrics(ObserverContext<MasterCoprocessorEnvironment> ctx, 207 ClusterMetrics status) throws IOException { 208 POST_COUNT.incrementAndGet(); 209 } 210 } 211}