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 zookeeper node on the given hostname or if this is a mini/local cluster,
167 * silently logs warning message.
168 * @param hostname the hostname to start the regionserver on
169 * @throws IOException if something goes wrong
170 */
171 public abstract void startZkNode(String hostname, int port) throws IOException;
172
173 /**
174 * Kills the zookeeper node process if this is a distributed cluster, otherwise,
175 * this causes master to exit doing basic clean up only.
176 * @throws IOException if something goes wrong
177 */
178 public abstract void killZkNode(ServerName serverName) throws IOException;
179
180 /**
181 * Stops the region zookeeper if this is a distributed cluster, otherwise
182 * silently logs warning message.
183 * @throws IOException if something goes wrong
184 */
185 public abstract void stopZkNode(ServerName serverName) throws IOException;
186
187 /**
188 * Wait for the specified zookeeper node to join the cluster
189 * @return whether the operation finished with success
190 * @throws IOException if something goes wrong or timeout occurs
191 */
192 public abstract void waitForZkNodeToStart(ServerName serverName, long timeout)
193 throws IOException;
194
195 /**
196 * Wait for the specified zookeeper node to stop the thread / process.
197 * @return whether the operation finished with success
198 * @throws IOException if something goes wrong or timeout occurs
199 */
200 public abstract void waitForZkNodeToStop(ServerName serverName, long timeout)
201 throws IOException;
202
203 /**
204 * Starts a new datanode on the given hostname or if this is a mini/local cluster,
205 * silently logs warning message.
206 * @throws IOException if something goes wrong
207 */
208 public abstract void startDataNode(ServerName serverName) throws IOException;
209
210 /**
211 * Kills the datanode process if this is a distributed cluster, otherwise,
212 * this causes master to exit doing basic clean up only.
213 * @throws IOException if something goes wrong
214 */
215 public abstract void killDataNode(ServerName serverName) throws IOException;
216
217 /**
218 * Stops the datanode if this is a distributed cluster, otherwise
219 * silently logs warning message.
220 * @throws IOException if something goes wrong
221 */
222 public abstract void stopDataNode(ServerName serverName) throws IOException;
223
224 /**
225 * Wait for the specified datanode to join the cluster
226 * @return whether the operation finished with success
227 * @throws IOException if something goes wrong or timeout occurs
228 */
229 public abstract void waitForDataNodeToStart(ServerName serverName, long timeout)
230 throws IOException;
231
232 /**
233 * Wait for the specified datanode to stop the thread / process.
234 * @return whether the operation finished with success
235 * @throws IOException if something goes wrong or timeout occurs
236 */
237 public abstract void waitForDataNodeToStop(ServerName serverName, long timeout)
238 throws IOException;
239
240 /**
241 * Starts a new master on the given hostname or if this is a mini/local cluster,
242 * starts a master locally.
243 * @param hostname the hostname to start the master on
244 * @return whether the operation finished with success
245 * @throws IOException if something goes wrong
246 */
247 public abstract void startMaster(String hostname, int port) throws IOException;
248
249 /**
250 * Kills the master process if this is a distributed cluster, otherwise,
251 * this causes master to exit doing basic clean up only.
252 * @throws IOException if something goes wrong
253 */
254 public abstract void killMaster(ServerName serverName) throws IOException;
255
256 /**
257 * Stops the given master, by attempting a gradual stop.
258 * @throws IOException if something goes wrong
259 */
260 public abstract void stopMaster(ServerName serverName) throws IOException;
261
262 /**
263 * Wait for the specified master to stop the thread / process.
264 * @throws IOException if something goes wrong or timeout occurs
265 */
266 public abstract void waitForMasterToStop(ServerName serverName, long timeout)
267 throws IOException;
268
269 /**
270 * Blocks until there is an active master and that master has completed
271 * initialization.
272 *
273 * @return true if an active master becomes available. false if there are no
274 * masters left.
275 * @throws IOException if something goes wrong or timeout occurs
276 */
277 public boolean waitForActiveAndReadyMaster()
278 throws IOException {
279 return waitForActiveAndReadyMaster(Long.MAX_VALUE);
280 }
281
282 /**
283 * Blocks until there is an active master and that master has completed
284 * initialization.
285 * @param timeout the timeout limit in ms
286 * @return true if an active master becomes available. false if there are no
287 * masters left.
288 */
289 public abstract boolean waitForActiveAndReadyMaster(long timeout)
290 throws IOException;
291
292 /**
293 * Wait for HBase Cluster to shut down.
294 */
295 public abstract void waitUntilShutDown() throws IOException;
296
297 /**
298 * Shut down the HBase cluster
299 */
300 public abstract void shutdown() throws IOException;
301
302 /**
303 * Restores the cluster to it's initial state if this is a real cluster,
304 * otherwise does nothing.
305 * This is a best effort restore. If the servers are not reachable, or insufficient
306 * permissions, etc. restoration might be partial.
307 * @return whether restoration is complete
308 */
309 public boolean restoreInitialStatus() throws IOException {
310 return restoreClusterStatus(getInitialClusterStatus());
311 }
312
313 /**
314 * Restores the cluster to given state if this is a real cluster,
315 * otherwise does nothing.
316 * This is a best effort restore. If the servers are not reachable, or insufficient
317 * permissions, etc. restoration might be partial.
318 * @return whether restoration is complete
319 */
320 public boolean restoreClusterStatus(ClusterStatus desiredStatus) throws IOException {
321 return true;
322 }
323
324 /**
325 * Get the ServerName of region server serving the first hbase:meta region
326 */
327 public ServerName getServerHoldingMeta() throws IOException {
328 return getServerHoldingRegion(TableName.META_TABLE_NAME,
329 HRegionInfo.FIRST_META_REGIONINFO.getRegionName());
330 }
331
332 /**
333 * Get the ServerName of region server serving the specified region
334 * @param regionName Name of the region in bytes
335 * @param tn Table name that has the region.
336 * @return ServerName that hosts the region or null
337 */
338 public abstract ServerName getServerHoldingRegion(final TableName tn, byte[] regionName)
339 throws IOException;
340
341 /**
342 * @return whether we are interacting with a distributed cluster as opposed to an
343 * in-process mini/local cluster.
344 */
345 public boolean isDistributedCluster() {
346 return false;
347 }
348
349 /**
350 * Closes all the resources held open for this cluster. Note that this call does not shutdown
351 * the cluster.
352 * @see #shutdown()
353 */
354 @Override
355 public abstract void close() throws IOException;
356
357 /**
358 * Wait for the namenode.
359 *
360 * @throws InterruptedException
361 */
362 public void waitForNamenodeAvailable() throws InterruptedException {
363 }
364
365 public void waitForDatanodesRegistered(int nbDN) throws Exception {
366 }
367 }