Skip to content

HBASE-29378 Make TestingHBaseCluster expose address/port information #7074

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@ public interface TestingHBaseCluster {
*/
List<ServerName> getRegionServerAddresses();

/**
* Get the web UI address of the active master if there is one.
*/
Optional<String> getActiveMasterInfoAddress();

/**
* Get the web UI address of the active NameNode if there is one.
*/
Optional<String> getActiveNameNodeInfoAddress();

/**
* Get the 'hbase.zookeeper.quorum' configuration value for the ZooKeeper cluster.
*/
Optional<String> getZooKeeperQuorum();

/**
* Get the list of master addresses.
*/
List<String> getMasterAddresses();

/**
* Get the server side {@link Region} interface for the specific region.
* <p/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
*/
package org.apache.hadoop.hbase.testing;

import static org.apache.hadoop.hbase.http.ServerConfigurationKeys.HBASE_SSL_ENABLED_KEY;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.hbase.HBaseTestingUtil;
Expand All @@ -37,6 +41,9 @@
import org.apache.hadoop.hbase.regionserver.Region;
import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread;
import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.server.namenode.NameNode;
import org.apache.yetus.audience.InterfaceAudience;

import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
Expand Down Expand Up @@ -147,7 +154,7 @@ public void startHBaseCluster() throws Exception {
public void start() throws Exception {
Preconditions.checkState(!miniClusterRunning, "Cluster has already been started");
if (externalZkConnectString == null) {
util.startMiniZKCluster();
util.startMiniZKCluster(option.getNumZkServers());
Copy link
Contributor Author

@junegunn junegunn Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While testing getZooKeeperQuorum, I noticed that numZkServers was never used. The fix is trivial (5bc0f4c), so I included it here, but if you think it deserves a separate issue, I'll split it.

} else {
Configuration conf = util.getConfiguration();
conf.set(HConstants.ZOOKEEPER_QUORUM, externalZkConnectString);
Expand Down Expand Up @@ -219,6 +226,76 @@ public List<ServerName> getRegionServerAddresses() {
.map(t -> t.getRegionServer().getServerName()).collect(Collectors.toList());
}

@Override
public Optional<String> getActiveMasterInfoAddress() {
final HMaster master = util.getMiniHBaseCluster().getMaster();

// No active master
if (master == null) {
return Optional.empty();
}

final Configuration conf = master.getConfiguration();
final int port = conf.getInt(HConstants.MASTER_INFO_PORT, 0);

// Web UI disabled
if (port <= 0) {
return Optional.empty();
}

final String protocol = conf.getBoolean(HBASE_SSL_ENABLED_KEY, false) ? "https" : "http";
final String hostname = master.getServerName().getHostname();
return Optional.of(String.format("%s://%s:%d", protocol, hostname, port));
}

@Override
public Optional<String> getActiveNameNodeInfoAddress() {
final MiniDFSCluster cluster = util.getDFSCluster();

// External DFS cluster
if (cluster == null) {
return Optional.empty();
}

final NameNode ann = Stream.of(cluster.getNameNodeInfos()).map(i -> i.nameNode)
.filter(NameNode::isActiveState).findFirst().orElse(null);

// No active NameNode
if (ann == null) {
return Optional.empty();
}

String protocol = "http";
InetSocketAddress address = ann.getHttpAddress();
if (address == null) {
protocol = "https";
address = ann.getHttpsAddress();
}

// Neither HTTP nor HTTPS address is available
if (address == null) {
return Optional.empty();
}

return Optional
.of(String.format("%s://%s:%d", protocol, address.getHostName(), address.getPort()));
}

@Override
public Optional<String> getZooKeeperQuorum() {
return Optional.ofNullable(util.getZkCluster())
.map(zk -> zk.getClientPortList().stream()
.map(port -> String.format("%s:%d", MiniZooKeeperCluster.HOST, port))
.collect(Collectors.joining(",")));
}

@Override
public List<String> getMasterAddresses() {
return util.getMiniHBaseCluster().getMasterThreads().stream()
.map(mt -> mt.getMaster().getServerName()).map(sn -> sn.getHostname() + ':' + sn.getPort())
.collect(Collectors.toList());
}

@Override
public Optional<Region> getRegion(RegionInfo regionInfo) {
for (RegionServerThread t : util.getMiniHBaseCluster().getRegionServerThreads()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@
import static org.junit.Assert.assertTrue;

import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.Waiter;
import org.apache.hadoop.hbase.client.Admin;
Expand Down Expand Up @@ -59,8 +65,10 @@ public class TestTestingHBaseCluster {

@BeforeClass
public static void setUpBeforeClass() throws Exception {
final Configuration conf = HBaseConfiguration.create();
conf.setInt(HConstants.MASTER_INFO_PORT, 0);
CLUSTER = TestingHBaseCluster.create(TestingHBaseClusterOption.builder().numMasters(2)
.numRegionServers(3).numDataNodes(3).build());
.numZkServers(3).numRegionServers(3).numDataNodes(3).conf(conf).build());
}

@AfterClass
Expand Down Expand Up @@ -150,5 +158,22 @@ public void testGetAddresses() throws Exception {
assertTrue(CLUSTER.getActiveMasterAddress().isPresent());
assertEquals(1, CLUSTER.getBackupMasterAddresses().size());
assertEquals(3, CLUSTER.getRegionServerAddresses().size());

// [HOSTNAME1:PORT1, HOSTNAME2:PORT2]
final List<String> masterAddrs = CLUSTER.getMasterAddresses();
assertEquals(2, masterAddrs.size());
assertTrue(masterAddrs.stream().allMatch(addr -> addr.matches(".*:[0-9]+$")));

// ZooKeeper quorum: localhost:PORT1,localhost:PORT2,localhost:PORT3
final String[] quorum = CLUSTER.getZooKeeperQuorum().orElse("").split(",");
assertEquals(3, quorum.length);
assertTrue(Stream.of(quorum).allMatch(a -> Pattern.matches(".*:[0-9]+$", a)));

// Web UI addresses
final String addressPattern = "^https?://.*:[0-9]+$";
assertTrue(CLUSTER.getActiveMasterInfoAddress().map(a -> Pattern.matches(addressPattern, a))
.orElse(false));
assertTrue(CLUSTER.getActiveNameNodeInfoAddress().map(a -> Pattern.matches(addressPattern, a))
.orElse(false));
}
}