You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iggy.apache.org by hg...@apache.org on 2026/10/18 15:34:32 UTC

(iggy) 14/23: fix(server-ng): report self-node listener ports in cluster metadata

This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch http-listener
in repository https://gitbox.apache.org/repos/asf/iggy.git

commit f13a94c208a4d52b245a058f2a545ce2286ec6b5
Author: Hubert Gruszecki <h....@gmail.com>
AuthorDate: Thu Jul 2 21:32:01 2026 +0200

    fix(server-ng): report self-node listener ports in cluster metadata
    
    In cluster-disabled mode GET /cluster/metadata synthesized the self
    node with tcp/quic/ws ports hardcoded to 0 even though bootstrap has
    the resolved listener addresses. Thread them into the HTTP roster so
    the fallback reports real ports (0 only for disabled transports).
---
 core/server-ng/src/bootstrap.rs | 11 ++++++++++-
 core/server-ng/src/http.rs      | 21 ++++++++++++++++-----
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/core/server-ng/src/bootstrap.rs b/core/server-ng/src/bootstrap.rs
index d346699da..751b3795f 100644
--- a/core/server-ng/src/bootstrap.rs
+++ b/core/server-ng/src/bootstrap.rs
@@ -1948,7 +1948,16 @@ async fn start_tcp_runtime(
     // caller of this function.
     if config.http.enabled {
         let http_addr = parse_socket_addr("http.address", &config.http.address)?;
-        http::start(shard, http_addr, &config.http, &config.cluster).await?;
+        let self_ports = configs::cluster::TransportPorts {
+            tcp: config
+                .tcp
+                .enabled
+                .then(|| topology.client_listen_addr.port()),
+            quic: topology.quic_listen_addr.map(|addr| addr.port()),
+            websocket: topology.ws_listen_addr.map(|addr| addr.port()),
+            ..Default::default()
+        };
+        http::start(shard, http_addr, &config.http, &config.cluster, self_ports).await?;
     }
 
     Ok(())
diff --git a/core/server-ng/src/http.rs b/core/server-ng/src/http.rs
index c98318633..8fb2a40c8 100644
--- a/core/server-ng/src/http.rs
+++ b/core/server-ng/src/http.rs
@@ -37,7 +37,7 @@ use axum::response::{IntoResponse, Response};
 use axum::routing::{delete, get, post, put};
 use axum::{Json, Router};
 use bytes::{Bytes, BytesMut};
-use configs::cluster::{ClusterConfig, ClusterNodeConfig};
+use configs::cluster::{ClusterConfig, ClusterNodeConfig, TransportPorts};
 use configs::http::HttpConfig;
 use consensus::{CLIENTS_TABLE_MAX, MetadataHandle, VsrConsensus};
 use futures::channel::oneshot;
@@ -640,8 +640,11 @@ struct ClusterRoster {
     name: String,
     nodes: Vec<ClusterNodeConfig>,
     /// This node's bound HTTP address, used to synthesize the sole self-node
-    /// when no roster is configured (the only transport port known here).
+    /// when no roster is configured.
     http_addr: SocketAddr,
+    /// This node's other client listener ports for the same self-node
+    /// synthesis (`None` = transport disabled; HTTP comes from `http_addr`).
+    self_ports: TransportPorts,
 }
 
 /// Serializes first-use VSR registration per credential key so a herd of
@@ -971,6 +974,7 @@ pub async fn start(
     addr: SocketAddr,
     http_config: &HttpConfig,
     cluster: &ClusterConfig,
+    self_ports: TransportPorts,
 ) -> Result<(), ServerNgError> {
     let jwt = JwtManager::build(&http_config.jwt)?;
     let (listener, bound_addr) = client_listener::tcp::bind(addr).await?;
@@ -986,6 +990,7 @@ pub async fn start(
             name: cluster.name.clone(),
             nodes: cluster.nodes.clone(),
             http_addr: bound_addr,
+            self_ports,
         },
         in_flight_writes: Cell::new(0),
     }));
@@ -2861,15 +2866,20 @@ fn build_cluster_metadata(state: &HttpInner) -> ClusterMetadata {
 }
 
 /// Synthesize a single self-node [`ClusterMetadata`], mirroring the legacy
-/// single-node path. Only this node's bound HTTP port is known at the HTTP layer
-/// (the roster is not threaded onto the shard), so the other transports report 0.
+/// single-node path: this node's own listener ports, with the HTTP port taken
+/// from the live bound address and disabled transports reporting 0.
 fn self_node_metadata(roster: &ClusterRoster) -> ClusterMetadata {
     ClusterMetadata {
         name: SINGLE_NODE_CLUSTER_NAME.to_owned(),
         nodes: vec![ClusterNode {
             name: SELF_NODE_NAME.to_owned(),
             ip: roster.http_addr.ip().to_string(),
-            endpoints: TransportEndpoints::new(0, 0, roster.http_addr.port(), 0),
+            endpoints: TransportEndpoints::new(
+                roster.self_ports.tcp.unwrap_or(0),
+                roster.self_ports.quic.unwrap_or(0),
+                roster.http_addr.port(),
+                roster.self_ports.websocket.unwrap_or(0),
+            ),
             role: ClusterNodeRole::Leader,
             status: ClusterNodeStatus::Healthy,
         }],
@@ -3191,6 +3201,7 @@ mod tests {
             name: "test-cluster".to_owned(),
             nodes,
             http_addr: "127.0.0.1:3000".parse().expect("valid socket addr"),
+            self_ports: TransportPorts::default(),
         }
     }