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.testing; 019 020import java.util.Arrays; 021import java.util.List; 022import org.apache.commons.lang3.StringUtils; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.StartMiniClusterOption; 025import org.apache.yetus.audience.InterfaceAudience; 026 027/** 028 * Options for starting up a mini testing cluster {@link TestingHBaseCluster} (including an hbase, 029 * dfs and zookeeper clusters) in test. The options include HDFS options to build mini dfs cluster, 030 * Zookeeper options to build mini zk cluster, and mostly HBase options to build mini hbase cluster. 031 * To create an object, use a {@link Builder}. Example usage: 032 * 033 * <pre> 034 * TestingHBaseClusterOption option = TestingHBaseClusterOption.builder(). 035 * .numMasters(3).createWALDir(true).build(); 036 * </pre> 037 * 038 * Default values can be found in {@link Builder}. 039 */ 040@InterfaceAudience.Public 041public final class TestingHBaseClusterOption { 042 043 /** 044 * Configuration for this testing cluster. Can be {@code null}. 045 */ 046 private final Configuration conf; 047 048 /** 049 * Number of masters to start up. We'll start this many hbase masters. 050 */ 051 private final int numMasters; 052 053 /** 054 * Number of masters that always remain standby. These set of masters never transition to active 055 * even if an active master does not exist. 056 */ 057 private final int numAlwaysStandByMasters; 058 059 /** 060 * Number of region servers to start up. If this value is > 1, then make sure config 061 * "hbase.regionserver.info.port" is -1 (i.e. no ui per regionserver) otherwise bind errors. 062 */ 063 private final int numRegionServers; 064 065 /** 066 * Ports that RegionServer should use. Pass ports if you want to test cluster restart where for 067 * sure the regionservers come up on same address+port (but just with different startcode); by 068 * default mini hbase clusters choose new arbitrary ports on each cluster start. 069 */ 070 private final List<Integer> rsPorts; 071 072 /** 073 * Number of datanodes. Used to create mini DSF cluster. Surpassed by {@link #dataNodeHosts} size. 074 */ 075 private final int numDataNodes; 076 077 /** 078 * The hostnames of DataNodes to run on. This is useful if you want to run datanode on distinct 079 * hosts for things like HDFS block location verification. If you start MiniDFSCluster without 080 * host names, all instances of the datanodes will have the same host name. 081 */ 082 private final String[] dataNodeHosts; 083 084 /** 085 * Number of Zookeeper servers. 086 */ 087 private final int numZkServers; 088 089 /** 090 * Whether to create a new root or data directory path. If true, the newly created data directory 091 * will be configured as HBase rootdir. This will overwrite existing root directory config. 092 */ 093 private final boolean createRootDir; 094 095 /** 096 * Whether to create a new WAL directory. If true, the newly created directory will be configured 097 * as HBase wal.dir which is separate from HBase rootdir. 098 */ 099 private final boolean createWALDir; 100 101 private final String externalDfsUri; 102 103 private final String externalZkConnectString; 104 105 /** 106 * Private constructor. Use {@link Builder#build()}. 107 */ 108 private TestingHBaseClusterOption(Configuration conf, int numMasters, int numAlwaysStandByMasters, 109 int numRegionServers, List<Integer> rsPorts, int numDataNodes, String[] dataNodeHosts, 110 int numZkServers, boolean createRootDir, boolean createWALDir, String externalDfsUri, 111 String externalZkConnectString) { 112 this.conf = conf; 113 this.numMasters = numMasters; 114 this.numAlwaysStandByMasters = numAlwaysStandByMasters; 115 this.numRegionServers = numRegionServers; 116 this.rsPorts = rsPorts; 117 this.numDataNodes = numDataNodes; 118 this.dataNodeHosts = dataNodeHosts; 119 this.numZkServers = numZkServers; 120 this.createRootDir = createRootDir; 121 this.createWALDir = createWALDir; 122 this.externalDfsUri = externalDfsUri; 123 this.externalZkConnectString = externalZkConnectString; 124 } 125 126 public Configuration conf() { 127 return conf; 128 } 129 130 public int getNumMasters() { 131 return numMasters; 132 } 133 134 public int getNumAlwaysStandByMasters() { 135 return numAlwaysStandByMasters; 136 } 137 138 public int getNumRegionServers() { 139 return numRegionServers; 140 } 141 142 public List<Integer> getRsPorts() { 143 return rsPorts; 144 } 145 146 public int getNumDataNodes() { 147 return numDataNodes; 148 } 149 150 public String[] getDataNodeHosts() { 151 return dataNodeHosts; 152 } 153 154 public int getNumZkServers() { 155 return numZkServers; 156 } 157 158 public boolean isCreateRootDir() { 159 return createRootDir; 160 } 161 162 public boolean isCreateWALDir() { 163 return createWALDir; 164 } 165 166 public String getExternalDfsUri() { 167 return externalDfsUri; 168 } 169 170 public String getExternalZkConnectString() { 171 return externalZkConnectString; 172 } 173 174 @Override 175 public String toString() { 176 return "StartMiniClusterOption{" + "numMasters=" + numMasters + ", numRegionServers=" 177 + numRegionServers + ", rsPorts=" + StringUtils.join(rsPorts) + ", numDataNodes=" 178 + numDataNodes + ", dataNodeHosts=" + Arrays.toString(dataNodeHosts) + ", numZkServers=" 179 + numZkServers + ", createRootDir=" + createRootDir + ", createWALDir=" + createWALDir + '}'; 180 } 181 182 /** 183 * Convert to the internal option. Not for public use so package private. 184 */ 185 StartMiniClusterOption convert() { 186 return StartMiniClusterOption.builder().numMasters(numMasters) 187 .numAlwaysStandByMasters(numAlwaysStandByMasters).numRegionServers(numRegionServers) 188 .rsPorts(rsPorts).numDataNodes(numDataNodes).dataNodeHosts(dataNodeHosts) 189 .numZkServers(numZkServers).createRootDir(createRootDir).createWALDir(createWALDir).build(); 190 } 191 192 /** 193 * Returns a new builder. 194 */ 195 public static Builder builder() { 196 return new Builder(); 197 } 198 199 /** 200 * Builder pattern for creating an {@link TestingHBaseClusterOption}. The default values of its 201 * fields should be considered public and constant. Changing the default values may cause other 202 * tests fail. 203 */ 204 public static final class Builder { 205 private Configuration conf; 206 private int numMasters = 1; 207 private int numAlwaysStandByMasters = 0; 208 private int numRegionServers = 1; 209 private List<Integer> rsPorts = null; 210 private int numDataNodes = 1; 211 private String[] dataNodeHosts = null; 212 private int numZkServers = 1; 213 private boolean createRootDir = false; 214 private boolean createWALDir = false; 215 private String externalDfsUri = null; 216 private String externalZkConnectString = null; 217 218 private Builder() { 219 } 220 221 public TestingHBaseClusterOption build() { 222 if (dataNodeHosts != null && dataNodeHosts.length != 0) { 223 numDataNodes = dataNodeHosts.length; 224 } 225 return new TestingHBaseClusterOption(conf, numMasters, numAlwaysStandByMasters, 226 numRegionServers, rsPorts, numDataNodes, dataNodeHosts, numZkServers, createRootDir, 227 createWALDir, externalDfsUri, externalZkConnectString); 228 } 229 230 public Builder conf(Configuration conf) { 231 this.conf = conf; 232 return this; 233 } 234 235 public Builder numMasters(int numMasters) { 236 this.numMasters = numMasters; 237 return this; 238 } 239 240 public Builder numAlwaysStandByMasters(int numAlwaysStandByMasters) { 241 this.numAlwaysStandByMasters = numAlwaysStandByMasters; 242 return this; 243 } 244 245 public Builder numRegionServers(int numRegionServers) { 246 this.numRegionServers = numRegionServers; 247 return this; 248 } 249 250 public Builder rsPorts(List<Integer> rsPorts) { 251 this.rsPorts = rsPorts; 252 return this; 253 } 254 255 public Builder numDataNodes(int numDataNodes) { 256 this.numDataNodes = numDataNodes; 257 return this; 258 } 259 260 public Builder dataNodeHosts(String[] dataNodeHosts) { 261 this.dataNodeHosts = dataNodeHosts; 262 return this; 263 } 264 265 public Builder numZkServers(int numZkServers) { 266 this.numZkServers = numZkServers; 267 return this; 268 } 269 270 public Builder createRootDir(boolean createRootDir) { 271 this.createRootDir = createRootDir; 272 return this; 273 } 274 275 public Builder createWALDir(boolean createWALDir) { 276 this.createWALDir = createWALDir; 277 return this; 278 } 279 280 public Builder useExternalDfs(String uri) { 281 this.externalDfsUri = uri; 282 return this; 283 } 284 285 public Builder useExternalZooKeeper(String connectString) { 286 this.externalZkConnectString = connectString; 287 return this; 288 } 289 } 290}