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 // Log is being used in DistributedHBaseCluster class, hence keeping it as package scope 60 static final Log LOG = LogFactory.getLog(HBaseCluster.class.getName()); 61 protected Configuration conf; 62 63 /** the status of the cluster before we begin */ 64 protected ClusterStatus initialClusterStatus; 65 66 /** 67 * Construct an HBaseCluster 68 * @param conf Configuration to be used for cluster 69 */ 70 public HBaseCluster(Configuration conf) { 71 setConf(conf); 72 } 73 74 @Override 75 public void setConf(Configuration conf) { 76 this.conf = conf; 77 } 78 79 @Override 80 public Configuration getConf() { 81 return conf; 82 } 83 84 /** 85 * Returns a ClusterStatus for this HBase cluster. 86 * @see #getInitialClusterStatus() 87 */ 88 public abstract ClusterStatus getClusterStatus() throws IOException; 89 90 /** 91 * Returns a ClusterStatus for this HBase cluster as observed at the 92 * starting of the HBaseCluster 93 */ 94 public ClusterStatus getInitialClusterStatus() throws IOException { 95 return initialClusterStatus; 96 } 97 98 /** 99 * Returns an {@link MasterService.BlockingInterface} to the active master 100 */ 101 public abstract MasterService.BlockingInterface getMasterAdminService() 102 throws IOException; 103 104 /** 105 * Returns an AdminProtocol interface to the regionserver 106 */ 107 public abstract AdminService.BlockingInterface getAdminProtocol(ServerName serverName) 108 throws IOException; 109 110 /** 111 * Returns a ClientProtocol interface to the regionserver 112 */ 113 public abstract ClientService.BlockingInterface getClientProtocol(ServerName serverName) 114 throws IOException; 115 116 /** 117 * Starts a new region server on the given hostname or if this is a mini/local cluster, 118 * starts a region server locally. 119 * @param hostname the hostname to start the regionserver on 120 * @throws IOException if something goes wrong 121 */ 122 public abstract void startRegionServer(String hostname, int port) throws IOException; 123 124 /** 125 * Kills the region server process if this is a distributed cluster, otherwise 126 * this causes the region server to exit doing basic clean up only. 127 * @throws IOException if something goes wrong 128 */ 129 public abstract void killRegionServer(ServerName serverName) throws IOException; 130 131 /** 132 * Stops the given region server, by attempting a gradual stop. 133 * @return whether the operation finished with success 134 * @throws IOException if something goes wrong 135 */ 136 public abstract void stopRegionServer(ServerName serverName) throws IOException; 137 138 /** 139 * Wait for the specified region server to join the cluster 140 * @return whether the operation finished with success 141 * @throws IOException if something goes wrong or timeout occurs 142 */ 143 public void waitForRegionServerToStart(String hostname, int port, long timeout) 144 throws IOException { 145 long start = System.currentTimeMillis(); 146 while ((System.currentTimeMillis() - start) < timeout) { 147 for (ServerName server : getClusterStatus().getServers()) { 148 if (server.getHostname().equals(hostname) && server.getPort() == port) { 149 return; 150 } 151 } 152 Threads.sleep(100); 153 } 154 throw new IOException("did timeout " + timeout + "ms waiting for region server to start: " 155 + hostname); 156 } 157 158 /** 159 * Wait for the specified region server to stop the thread / process. 160 * @return whether the operation finished with success 161 * @throws IOException if something goes wrong or timeout occurs 162 */ 163 public abstract void waitForRegionServerToStop(ServerName serverName, long timeout) 164 throws IOException; 165 166 /** 167 * Starts a new zookeeper node on the given hostname or if this is a mini/local cluster, 168 * silently logs warning message. 169 * @param hostname the hostname to start the regionserver on 170 * @throws IOException if something goes wrong 171 */ 172 public abstract void startZkNode(String hostname, int port) throws IOException; 173 174 /** 175 * Kills the zookeeper node 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 killZkNode(ServerName serverName) throws IOException; 180 181 /** 182 * Stops the region zookeeper if this is a distributed cluster, otherwise 183 * silently logs warning message. 184 * @throws IOException if something goes wrong 185 */ 186 public abstract void stopZkNode(ServerName serverName) throws IOException; 187 188 /** 189 * Wait for the specified zookeeper node to join the cluster 190 * @return whether the operation finished with success 191 * @throws IOException if something goes wrong or timeout occurs 192 */ 193 public abstract void waitForZkNodeToStart(ServerName serverName, long timeout) 194 throws IOException; 195 196 /** 197 * Wait for the specified zookeeper node to stop the thread / process. 198 * @return whether the operation finished with success 199 * @throws IOException if something goes wrong or timeout occurs 200 */ 201 public abstract void waitForZkNodeToStop(ServerName serverName, long timeout) 202 throws IOException; 203 204 /** 205 * Starts a new datanode on the given hostname or if this is a mini/local cluster, 206 * silently logs warning message. 207 * @throws IOException if something goes wrong 208 */ 209 public abstract void startDataNode(ServerName serverName) throws IOException; 210 211 /** 212 * Kills the datanode process if this is a distributed cluster, otherwise, 213 * this causes master to exit doing basic clean up only. 214 * @throws IOException if something goes wrong 215 */ 216 public abstract void killDataNode(ServerName serverName) throws IOException; 217 218 /** 219 * Stops the datanode if this is a distributed cluster, otherwise 220 * silently logs warning message. 221 * @throws IOException if something goes wrong 222 */ 223 public abstract void stopDataNode(ServerName serverName) throws IOException; 224 225 /** 226 * Wait for the specified datanode to join the cluster 227 * @return whether the operation finished with success 228 * @throws IOException if something goes wrong or timeout occurs 229 */ 230 public abstract void waitForDataNodeToStart(ServerName serverName, long timeout) 231 throws IOException; 232 233 /** 234 * Wait for the specified datanode to stop the thread / process. 235 * @return whether the operation finished with success 236 * @throws IOException if something goes wrong or timeout occurs 237 */ 238 public abstract void waitForDataNodeToStop(ServerName serverName, long timeout) 239 throws IOException; 240 241 /** 242 * Starts a new master on the given hostname or if this is a mini/local cluster, 243 * starts a master locally. 244 * @param hostname the hostname to start the master on 245 * @return whether the operation finished with success 246 * @throws IOException if something goes wrong 247 */ 248 public abstract void startMaster(String hostname, int port) throws IOException; 249 250 /** 251 * Kills the master process if this is a distributed cluster, otherwise, 252 * this causes master to exit doing basic clean up only. 253 * @throws IOException if something goes wrong 254 */ 255 public abstract void killMaster(ServerName serverName) throws IOException; 256 257 /** 258 * Stops the given master, by attempting a gradual stop. 259 * @throws IOException if something goes wrong 260 */ 261 public abstract void stopMaster(ServerName serverName) throws IOException; 262 263 /** 264 * Wait for the specified master to stop the thread / process. 265 * @throws IOException if something goes wrong or timeout occurs 266 */ 267 public abstract void waitForMasterToStop(ServerName serverName, long timeout) 268 throws IOException; 269 270 /** 271 * Blocks until there is an active master and that master has completed 272 * initialization. 273 * 274 * @return true if an active master becomes available. false if there are no 275 * masters left. 276 * @throws IOException if something goes wrong or timeout occurs 277 */ 278 public boolean waitForActiveAndReadyMaster() 279 throws IOException { 280 return waitForActiveAndReadyMaster(Long.MAX_VALUE); 281 } 282 283 /** 284 * Blocks until there is an active master and that master has completed 285 * initialization. 286 * @param timeout the timeout limit in ms 287 * @return true if an active master becomes available. false if there are no 288 * masters left. 289 */ 290 public abstract boolean waitForActiveAndReadyMaster(long timeout) 291 throws IOException; 292 293 /** 294 * Wait for HBase Cluster to shut down. 295 */ 296 public abstract void waitUntilShutDown() throws IOException; 297 298 /** 299 * Shut down the HBase cluster 300 */ 301 public abstract void shutdown() throws IOException; 302 303 /** 304 * Restores the cluster to it's initial state if this is a real cluster, 305 * otherwise does nothing. 306 * This is a best effort restore. If the servers are not reachable, or insufficient 307 * permissions, etc. restoration might be partial. 308 * @return whether restoration is complete 309 */ 310 public boolean restoreInitialStatus() throws IOException { 311 return restoreClusterStatus(getInitialClusterStatus()); 312 } 313 314 /** 315 * Restores the cluster to given state if this is a real cluster, 316 * otherwise does nothing. 317 * This is a best effort restore. If the servers are not reachable, or insufficient 318 * permissions, etc. restoration might be partial. 319 * @return whether restoration is complete 320 */ 321 public boolean restoreClusterStatus(ClusterStatus desiredStatus) throws IOException { 322 return true; 323 } 324 325 /** 326 * Get the ServerName of region server serving the first hbase:meta region 327 */ 328 public ServerName getServerHoldingMeta() throws IOException { 329 return getServerHoldingRegion(TableName.META_TABLE_NAME, 330 HRegionInfo.FIRST_META_REGIONINFO.getRegionName()); 331 } 332 333 /** 334 * Get the ServerName of region server serving the specified region 335 * @param regionName Name of the region in bytes 336 * @param tn Table name that has the region. 337 * @return ServerName that hosts the region or null 338 */ 339 public abstract ServerName getServerHoldingRegion(final TableName tn, byte[] regionName) 340 throws IOException; 341 342 /** 343 * @return whether we are interacting with a distributed cluster as opposed to an 344 * in-process mini/local cluster. 345 */ 346 public boolean isDistributedCluster() { 347 return false; 348 } 349 350 /** 351 * Closes all the resources held open for this cluster. Note that this call does not shutdown 352 * the cluster. 353 * @see #shutdown() 354 */ 355 @Override 356 public abstract void close() throws IOException; 357 358 /** 359 * Wait for the namenode. 360 * 361 * @throws InterruptedException 362 */ 363 public void waitForNamenodeAvailable() throws InterruptedException { 364 } 365 366 public void waitForDatanodesRegistered(int nbDN) throws Exception { 367 } 368 }