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