This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new ca7d5d894fd HDDS-15768. Bracket IPv6 literals in Ratis peer addresses
(#10686)
ca7d5d894fd is described below
commit ca7d5d894fd21519e09ca6592a1ac2a2a014473e
Author: Siyao Meng <[email protected]>
AuthorDate: Fri Jul 10 02:35:30 2026 -0700
HDDS-15768. Bracket IPv6 literals in Ratis peer addresses (#10686)
Generated-by: Claude Code (Opus 4.8)
---
AGENTS.md | 2 +-
.../main/java/org/apache/hadoop/hdds/HddsUtils.java | 15 +++++++++++++++
.../java/org/apache/hadoop/hdds/NodeDetails.java | 6 +-----
.../org/apache/hadoop/hdds/ratis/RatisHelper.java | 20 ++++++++------------
.../java/org/apache/hadoop/hdds/TestHddsUtils.java | 15 +++++++++++++++
.../apache/hadoop/hdds/ratis/TestRatisHelper.java | 15 +++++++++++++++
6 files changed, 55 insertions(+), 18 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index 95d60ed5b73..5bd695b1f43 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -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.
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
index bf4213ea8dc..335b8934c21 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
@@ -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
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/NodeDetails.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/NodeDetails.java
index 0984048bd51..ae871a8a86f 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/NodeDetails.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/NodeDetails.java
@@ -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() {
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/ratis/RatisHelper.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/ratis/RatisHelper.java
index b2813bad1e2..4a30248f4a7 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/ratis/RatisHelper.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/ratis/RatisHelper.java
@@ -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;
@@ -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) {
diff --git
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/TestHddsUtils.java
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/TestHddsUtils.java
index 650db8c5439..95e2cb2d564 100644
--- a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/TestHddsUtils.java
+++ b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/TestHddsUtils.java
@@ -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("/", "/"),
diff --git
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/ratis/TestRatisHelper.java
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/ratis/TestRatisHelper.java
index 2f10f550bb5..aab920954f7 100644
---
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/ratis/TestRatisHelper.java
+++
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/ratis/TestRatisHelper.java
@@ -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;
/**
@@ -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());
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]