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