1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hbase; 19 20 import java.io.Closeable; 21 import java.io.IOException; 22 23 import org.apache.commons.logging.Log; 24 import org.apache.commons.logging.LogFactory; 25 import org.apache.hadoop.hbase.classification.InterfaceAudience; 26 import org.apache.hadoop.conf.Configurable; 27 import org.apache.hadoop.conf.Configuration; 28 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService; 29 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ClientService; 30 import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MasterService; 31 import org.apache.hadoop.hbase.util.Threads; 32 33 /** 34 * This class defines methods that can help with managing HBase clusters 35 * from unit tests and system tests. There are 3 types of cluster deployments: 36 * <ul> 37 * <li><b>MiniHBaseCluster:</b> each server is run in the same JVM in separate threads, 38 * used by unit tests</li> 39 * <li><b>DistributedHBaseCluster:</b> the cluster is pre-deployed, system and integration tests can 40 * interact with the cluster. </li> 41 * <li><b>ProcessBasedLocalHBaseCluster:</b> each server is deployed locally but in separate 42 * JVMs. </li> 43 * </ul> 44 * <p> 45 * HBaseCluster unifies the way tests interact with the cluster, so that the same test can 46 * be run against a mini-cluster during unit test execution, or a distributed cluster having 47 * tens/hundreds of nodes during execution of integration tests. 48 * 49 * <p> 50 * HBaseCluster exposes client-side public interfaces to tests, so that tests does not assume 51 * running in a particular mode. Not all the tests are suitable to be run on an actual cluster, 52 * and some tests will still need to mock stuff and introspect internal state. For those use 53 * cases from unit tests, or if more control is needed, you can use the subclasses directly. 54 * In that sense, this class does not abstract away <strong>every</strong> interface that 55 * MiniHBaseCluster or DistributedHBaseCluster provide. 56 */ 57 @InterfaceAudience.Private 58 public abstract class HBaseCluster implements Closeable, Configurable { 59 static final Log LOG = LogFactory.getLog(HBaseCluster.class.getName()); 60 protected Configuration conf; 61 62 /** the status of the cluster before we begin */ 63 protected ClusterStatus initialClusterStatus; 64 65 /** 66 * Construct an HBaseCluster 67 * @param conf Configuration to be used for cluster 68 */ 69 public HBaseCluster(Configuration conf) { 70 setConf(conf); 71 } 72 73 @Override 74 public void setConf(Configuration conf) { 75 this.conf = conf; 76 } 77 78 @Override 79 public Configuration getConf() { 80 return conf; 81 } 82 83 /** 84 * Returns a ClusterStatus for this HBase cluster. 85 * @see #getInitialClusterStatus() 86 */ 87 public abstract ClusterStatus getClusterStatus() throws IOException; 88 89 /** 90 * Returns a ClusterStatus for this HBase cluster as observed at the 91 * starting of the HBaseCluster 92 */ 93 public ClusterStatus getInitialClusterStatus() throws IOException { 94 return initialClusterStatus; 95 } 96 97 /** 98 * Returns an {@link MasterService.BlockingInterface} to the active master 99 */ 100 public abstract MasterService.BlockingInterface getMasterAdminService() 101 throws IOException; 102 103 /** 104 * Returns an AdminProtocol interface to the regionserver 105 */ 106 public abstract AdminService.BlockingInterface getAdminProtocol(ServerName serverName) 107 throws IOException; 108 109 /** 110 * Returns a ClientProtocol interface to the regionserver 111 */ 112 public abstract ClientService.BlockingInterface getClientProtocol(ServerName serverName) 113 throws IOException; 114 115 /** 116 * Starts a new region server on the given hostname or if this is a mini/local cluster, 117 * starts a region server locally. 118 * @param hostname the hostname to start the regionserver on 119 * @throws IOException if something goes wrong 120 */ 121 public abstract void startRegionServer(String hostname, int port) throws IOException; 122 123 /** 124 * Kills the region server process if this is a distributed cluster, otherwise 125 * this causes the region server to exit doing basic clean up only. 126 * @throws IOException if something goes wrong 127 */ 128 public abstract void killRegionServer(ServerName serverName) throws IOException; 129 130 /** 131 * Stops the given region server, by attempting a gradual stop. 132 * @return whether the operation finished with success 133 * @throws IOException if something goes wrong 134 */ 135 public abstract void stopRegionServer(ServerName serverName) throws IOException; 136 137 /** 138 * Wait for the specified region server to join the cluster 139 * @return whether the operation finished with success 140 * @throws IOException if something goes wrong or timeout occurs 141 */ 142 public void waitForRegionServerToStart(String hostname, int port, long timeout) 143 throws IOException { 144 long start = System.currentTimeMillis(); 145 while ((System.currentTimeMillis() - start) < timeout) { 146 for (ServerName server : getClusterStatus().getServers()) { 147 if (server.getHostname().equals(hostname) && server.getPort() == port) { 148 return; 149 } 150 } 151 Threads.sleep(100); 152 } 153 throw new IOException("did timeout " + timeout + "ms waiting for region server to start: " 154 + hostname); 155 } 156 157 /** 158 * Wait for the specified region server to stop the thread / process. 159 * @return whether the operation finished with success 160 * @throws IOException if something goes wrong or timeout occurs 161 */ 162 public abstract void waitForRegionServerToStop(ServerName serverName, long timeout) 163 throws IOException; 164 165 /** 166 * Starts a new master on the given hostname or if this is a mini/local cluster, 167 * starts a master locally. 168 * @param hostname the hostname to start the master on 169 * @return whether the operation finished with success 170 * @throws IOException if something goes wrong 171 */ 172 public abstract void startMaster(String hostname, int port) throws IOException; 173 174 /** 175 * Kills the master process if this is a distributed cluster, otherwise, 176 * this causes master to exit doing basic clean up only. 177 * @throws IOException if something goes wrong 178 */ 179 public abstract void killMaster(ServerName serverName) throws IOException; 180 181 /** 182 * Stops the given master, by attempting a gradual stop. 183 * @throws IOException if something goes wrong 184 */ 185 public abstract void stopMaster(ServerName serverName) throws IOException; 186 187 /** 188 * Wait for the specified master to stop the thread / process. 189 * @throws IOException if something goes wrong or timeout occurs 190 */ 191 public abstract void waitForMasterToStop(ServerName serverName, long timeout) 192 throws IOException; 193 194 /** 195 * Blocks until there is an active master and that master has completed 196 * initialization. 197 * 198 * @return true if an active master becomes available. false if there are no 199 * masters left. 200 * @throws IOException if something goes wrong or timeout occurs 201 */ 202 public boolean waitForActiveAndReadyMaster() 203 throws IOException { 204 return waitForActiveAndReadyMaster(Long.MAX_VALUE); 205 } 206 207 /** 208 * Blocks until there is an active master and that master has completed 209 * initialization. 210 * @param timeout the timeout limit in ms 211 * @return true if an active master becomes available. false if there are no 212 * masters left. 213 */ 214 public abstract boolean waitForActiveAndReadyMaster(long timeout) 215 throws IOException; 216 217 /** 218 * Wait for HBase Cluster to shut down. 219 */ 220 public abstract void waitUntilShutDown() throws IOException; 221 222 /** 223 * Shut down the HBase cluster 224 */ 225 public abstract void shutdown() throws IOException; 226 227 /** 228 * Restores the cluster to it's initial state if this is a real cluster, 229 * otherwise does nothing. 230 * This is a best effort restore. If the servers are not reachable, or insufficient 231 * permissions, etc. restoration might be partial. 232 * @return whether restoration is complete 233 */ 234 public boolean restoreInitialStatus() throws IOException { 235 return restoreClusterStatus(getInitialClusterStatus()); 236 } 237 238 /** 239 * Restores the cluster to given state if this is a real cluster, 240 * otherwise does nothing. 241 * This is a best effort restore. If the servers are not reachable, or insufficient 242 * permissions, etc. restoration might be partial. 243 * @return whether restoration is complete 244 */ 245 public boolean restoreClusterStatus(ClusterStatus desiredStatus) throws IOException { 246 return true; 247 } 248 249 /** 250 * Get the ServerName of region server serving the first hbase:meta region 251 */ 252 public ServerName getServerHoldingMeta() throws IOException { 253 return getServerHoldingRegion(TableName.META_TABLE_NAME, 254 HRegionInfo.FIRST_META_REGIONINFO.getRegionName()); 255 } 256 257 /** 258 * Get the ServerName of region server serving the specified region 259 * @param regionName Name of the region in bytes 260 * @param tn Table name that has the region. 261 * @return ServerName that hosts the region or null 262 */ 263 public abstract ServerName getServerHoldingRegion(final TableName tn, byte[] regionName) 264 throws IOException; 265 266 /** 267 * @return whether we are interacting with a distributed cluster as opposed to an 268 * in-process mini/local cluster. 269 */ 270 public boolean isDistributedCluster() { 271 return false; 272 } 273 274 /** 275 * Closes all the resources held open for this cluster. Note that this call does not shutdown 276 * the cluster. 277 * @see #shutdown() 278 */ 279 @Override 280 public abstract void close() throws IOException; 281 282 /** 283 * Wait for the namenode. 284 * 285 * @throws InterruptedException 286 */ 287 public void waitForNamenodeAvailable() throws InterruptedException { 288 } 289 290 public void waitForDatanodesRegistered(int nbDN) throws Exception { 291 } 292 }