Skip to content
Merged
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- Reuse existing Ozone and Ratis utilities when the surrounding code already uses them.
Prefer extending an existing helper over duplicating logic or adding a new one-off abstraction.
- If there are multiple reasonable interpretations, state the tradeoff and ask instead of guessing.
- Do not wrap lines early just to make them look uniform. The project limit is 120 characters; use the space.
- Do not wrap lines early just to make them look uniform. The checkstyle maximum (see `hadoop-hdds/dev-support/checkstyle/checkstyle.xml`) is 120 characters for Java. Use the full 120 characters before wrapping; never break a line that fits on one line.
- Use established Ozone vocabulary in code, docs, and PR text:
SCM, OM, datanode, container, pipeline, volume, bucket, key, snapshot,
Recon, FSO, OBS, and S3 Gateway.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,21 @@ public static OptionalInt getHostPort(String value) {
}
}

/**
* Combine a host and port into a "host:port" string, wrapping the host in
* square brackets when it is an IPv6 literal (for example
* {@code [2001:db8::1]:9858}). A bare IPv6 literal joined to a port with a
* plain colon is ambiguous and cannot be parsed by Ratis/gRPC targets or
* URI-based address parsers.
*
* @param host a hostname, IPv4 literal, or (bracketed or bare) IPv6 literal
* @param port the port number
* @return the combined address, bracketed for IPv6 literals
*/
public static String getHostPortString(String host, int port) {
return HostAndPort.fromParts(host, port).toString();
}

/**
* Retrieve a number, trying the supplied config keys in order.
* Each config value may be absent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,7 @@ public String getHostAddress() {
}

public String getRatisHostPortStr() {
StringBuilder hostPort = new StringBuilder();
hostPort.append(getHostName())
.append(':')
.append(ratisPort);
return hostPort.toString();
return HddsUtils.getHostPortString(getHostName(), ratisPort);
}

public int getRatisPort() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.stream.Collectors;
import javax.net.ssl.TrustManager;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.HddsUtils;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
Expand Down Expand Up @@ -125,18 +126,13 @@ public static UUID toDatanodeId(RaftProtos.RaftPeerProto peerId) {
}

private static String toRaftPeerAddress(DatanodeDetails id, Port.Name port) {
if (datanodeUseHostName()) {
final String address =
id.getHostName() + ":" + id.getPort(port).getValue();
LOG.debug("Datanode is using hostname for raft peer address: {}",
address);
return address;
} else {
final String address =
id.getIpAddress() + ":" + id.getPort(port).getValue();
LOG.debug("Datanode is using IP for raft peer address: {}", address);
return address;
}
final boolean useHostName = datanodeUseHostName();
final String address = HddsUtils.getHostPortString(
useHostName ? id.getHostName() : id.getIpAddress(),
id.getPort(port).getValue());
LOG.debug("Datanode is using {} for raft peer address: {}",
useHostName ? "hostname" : "IP", address);
return address;
}

public static RaftPeerId toRaftPeerId(DatanodeDetails id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ void testGetHostName() {
HddsUtils.getHostName(":1234"));
}

@Test
void testGetHostPortString() {
// Hostnames and IPv4 literals are joined with a plain colon.
assertEquals("host1:9858", HddsUtils.getHostPortString("host1", 9858));
assertEquals("1.2.3.4:9858", HddsUtils.getHostPortString("1.2.3.4", 9858));

// Bare IPv6 literals must be bracketed so the result is an unambiguous
// Ratis/gRPC target.
assertEquals("[2001:db8::1]:9858", HddsUtils.getHostPortString("2001:db8::1", 9858));
assertEquals("[::1]:9858", HddsUtils.getHostPortString("::1", 9858));

// Already-bracketed IPv6 literals keep a single pair of brackets.
assertEquals("[2001:db8::1]:9858", HddsUtils.getHostPortString("[2001:db8::1]", 9858));
}

static List<Arguments> validPaths() {
return Arrays.asList(
Arguments.of("/", "/"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
import static org.junit.jupiter.api.Assertions.assertNull;

import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeID;
import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import org.apache.ratis.conf.RaftProperties;
import org.apache.ratis.protocol.RaftPeer;
import org.junit.jupiter.api.Test;

/**
Expand Down Expand Up @@ -122,4 +126,15 @@ public void testCreateRaftServerProperties() {
assertNull(raftProperties.get("raft.client.rpc.request.timeout"));

}

@Test
public void testRaftPeerAddressBracketsIpv6() {
// hdds.datanode.use.datanode.hostname defaults to false, so the datanode
// IP is used for the raft peer address. An IPv6 literal must be bracketed
// for the Ratis/gRPC peer target to be parsed correctly.
DatanodeDetails dn = MockDatanodeDetails.createDatanodeDetails(
DatanodeID.randomID(), "dn-ipv6", "2001:db8::1", "/default-rack");
RaftPeer peer = RatisHelper.toRaftPeer(dn);
assertEquals("[2001:db8::1]:0", peer.getAddress());
}
}
Loading