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