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.File; 021import java.io.IOException; 022import java.util.UUID; 023 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.fs.Path; 026import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster; 027import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 028import org.apache.yetus.audience.InterfaceAudience; 029 030/** 031 * Helpers for testing HBase that do not depend on specific server/etc. things. The main difference 032 * from {@link HBaseCommonTestingUtility} is that we can start a zookeeper cluster. 033 */ 034@InterfaceAudience.Public 035public class HBaseZKTestingUtility extends HBaseCommonTestingUtility { 036 037 private MiniZooKeeperCluster zkCluster; 038 039 /** 040 * Set if we were passed a zkCluster. If so, we won't shutdown zk as part of general shutdown. 041 */ 042 private boolean passedZkCluster; 043 044 protected ZKWatcher zooKeeperWatcher; 045 046 /** Directory (a subdirectory of dataTestDir) used by the dfs cluster if any */ 047 protected File clusterTestDir; 048 049 public HBaseZKTestingUtility() { 050 this(HBaseConfiguration.create()); 051 } 052 053 public HBaseZKTestingUtility(Configuration conf) { 054 super(conf); 055 } 056 057 /** 058 * @return Where the cluster will write data on the local subsystem. Creates it if it does not 059 * exist already. A subdir of {@link #getBaseTestDir()} 060 * @see #getTestFileSystem() 061 */ 062 Path getClusterTestDir() { 063 if (clusterTestDir == null) { 064 setupClusterTestDir(); 065 } 066 return new Path(clusterTestDir.getAbsolutePath()); 067 } 068 069 /** 070 * Creates a directory for the cluster, under the test data 071 */ 072 protected void setupClusterTestDir() { 073 if (clusterTestDir != null) { 074 return; 075 } 076 077 // Using randomUUID ensures that multiple clusters can be launched by 078 // a same test, if it stops & starts them 079 Path testDir = getDataTestDir("cluster_" + UUID.randomUUID().toString()); 080 clusterTestDir = new File(testDir.toString()).getAbsoluteFile(); 081 // Have it cleaned up on exit 082 boolean b = deleteOnExit(); 083 if (b) { 084 clusterTestDir.deleteOnExit(); 085 } 086 LOG.info("Created new mini-cluster data directory: " + clusterTestDir + ", deleteOnExit=" + b); 087 } 088 089 /** 090 * Call this if you only want a zk cluster. 091 * @see #shutdownMiniZKCluster() 092 * @return zk cluster started. 093 */ 094 public MiniZooKeeperCluster startMiniZKCluster() throws Exception { 095 return startMiniZKCluster(1); 096 } 097 098 /** 099 * Call this if you only want a zk cluster. 100 * @see #shutdownMiniZKCluster() 101 * @return zk cluster started. 102 */ 103 public MiniZooKeeperCluster startMiniZKCluster(int zooKeeperServerNum, int... clientPortList) 104 throws Exception { 105 setupClusterTestDir(); 106 return startMiniZKCluster(clusterTestDir, zooKeeperServerNum, clientPortList); 107 } 108 109 /** 110 * Start a mini ZK cluster. If the property "test.hbase.zookeeper.property.clientPort" is set the 111 * port mentioned is used as the default port for ZooKeeper. 112 */ 113 private MiniZooKeeperCluster startMiniZKCluster(File dir, int zooKeeperServerNum, 114 int[] clientPortList) throws Exception { 115 if (this.zkCluster != null) { 116 throw new IOException("Cluster already running at " + dir); 117 } 118 this.passedZkCluster = false; 119 this.zkCluster = new MiniZooKeeperCluster(this.getConfiguration()); 120 int defPort = this.conf.getInt("test.hbase.zookeeper.property.clientPort", 0); 121 if (defPort > 0) { 122 // If there is a port in the config file, we use it. 123 this.zkCluster.setDefaultClientPort(defPort); 124 } 125 126 if (clientPortList != null) { 127 // Ignore extra client ports 128 int clientPortListSize = (clientPortList.length <= zooKeeperServerNum) ? clientPortList.length 129 : zooKeeperServerNum; 130 for (int i = 0; i < clientPortListSize; i++) { 131 this.zkCluster.addClientPort(clientPortList[i]); 132 } 133 } 134 int clientPort = this.zkCluster.startup(dir, zooKeeperServerNum); 135 this.conf.set(HConstants.ZOOKEEPER_CLIENT_PORT, Integer.toString(clientPort)); 136 return this.zkCluster; 137 } 138 139 public MiniZooKeeperCluster getZkCluster() { 140 return zkCluster; 141 } 142 143 public void setZkCluster(MiniZooKeeperCluster zkCluster) { 144 this.passedZkCluster = true; 145 this.zkCluster = zkCluster; 146 conf.setInt(HConstants.ZOOKEEPER_CLIENT_PORT, zkCluster.getClientPort()); 147 } 148 149 /** 150 * Shuts down zk cluster created by call to {@link #startMiniZKCluster(File)} or does nothing. 151 * @see #startMiniZKCluster() 152 */ 153 public void shutdownMiniZKCluster() throws IOException { 154 if (!passedZkCluster && this.zkCluster != null) { 155 this.zkCluster.shutdown(); 156 this.zkCluster = null; 157 } 158 } 159 160 /** 161 * Returns a ZKWatcher instance. This instance is shared between HBaseTestingUtility instance 162 * users. Don't close it, it will be closed automatically when the cluster shutdowns 163 * @return The ZKWatcher instance. 164 */ 165 public synchronized ZKWatcher getZooKeeperWatcher() throws IOException { 166 if (zooKeeperWatcher == null) { 167 zooKeeperWatcher = new ZKWatcher(conf, "testing utility", new Abortable() { 168 @Override 169 public void abort(String why, Throwable e) { 170 throw new RuntimeException("Unexpected abort in HBaseZKTestingUtility:" + why, e); 171 } 172 173 @Override 174 public boolean isAborted() { 175 return false; 176 } 177 }); 178 } 179 return zooKeeperWatcher; 180 } 181 182 /** 183 * Gets a ZKWatcher. 184 */ 185 public static ZKWatcher getZooKeeperWatcher(HBaseZKTestingUtility testUtil) 186 throws ZooKeeperConnectionException, IOException { 187 ZKWatcher zkw = new ZKWatcher(testUtil.getConfiguration(), "unittest", new Abortable() { 188 boolean aborted = false; 189 190 @Override 191 public void abort(String why, Throwable e) { 192 aborted = true; 193 throw new RuntimeException("Fatal ZK error, why=" + why, e); 194 } 195 196 @Override 197 public boolean isAborted() { 198 return aborted; 199 } 200 }); 201 return zkw; 202 } 203 204 /** 205 * @return True if we removed the test dirs 206 */ 207 @Override 208 public boolean cleanupTestDir() throws IOException { 209 boolean ret = super.cleanupTestDir(); 210 if (deleteDir(this.clusterTestDir)) { 211 this.clusterTestDir = null; 212 return ret & true; 213 } 214 return false; 215 } 216}