feat(cluster): add iroh-gossip dependencies and cluster config schema

Add iroh v0.96, iroh-gossip v0.96, blake3, hex, and rand v0.9 to
Cargo.toml. Define ClusterConfig, DiscoveryConfig, BandwidthClusterConfig,
and ModelsConfig in config.rs with serde defaults for gossip port (11204),
broadcast interval (1s), meter window (30s), and peer discovery methods
(k8s/bootstrap).

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
This commit is contained in:
2026-03-10 23:38:20 +00:00
parent 2660ee974c
commit ad5c7f0afb
3 changed files with 2143 additions and 16 deletions

2069
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -71,6 +71,13 @@ kube = { version = "3", features = ["runtime", "client"] }
k8s-openapi = { version = "0.27", features = ["v1_35"] }
libc = "0.2"
# Cluster gossip (iroh QUIC + HyParView/PlumTree)
iroh = "0.96"
iroh-gossip = { version = "0.96", features = ["net"] }
blake3 = "1"
hex = "0.4"
rand = "0.9"
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
proptest = "1"

View File

@@ -27,6 +27,8 @@ pub struct Config {
/// Kubernetes resource names and namespaces for watchers.
#[serde(default)]
pub kubernetes: KubernetesConfig,
/// Optional gossip-based cluster for multi-node state sharing.
pub cluster: Option<ClusterConfig>,
}
#[derive(Debug, Deserialize, Clone)]
@@ -274,6 +276,87 @@ pub struct RouteConfig {
pub cache: Option<CacheConfig>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct ClusterConfig {
#[serde(default = "default_cluster_enabled")]
pub enabled: bool,
/// Tenant UUID — isolates unrelated deployments.
pub tenant: String,
/// UDP port for gossip protocol.
#[serde(default = "default_gossip_port")]
pub gossip_port: u16,
/// Path to persist the node identity key.
#[serde(default)]
pub key_path: Option<String>,
/// Peer discovery configuration.
#[serde(default)]
pub discovery: DiscoveryConfig,
/// Bandwidth broadcast settings.
#[serde(default)]
pub bandwidth: Option<BandwidthClusterConfig>,
/// Model distribution settings.
#[serde(default)]
pub models: Option<ModelsConfig>,
}
fn default_cluster_enabled() -> bool { true }
fn default_gossip_port() -> u16 { 11204 }
#[derive(Debug, Deserialize, Clone)]
pub struct DiscoveryConfig {
/// "k8s" or "bootstrap".
#[serde(default = "default_discovery_method")]
pub method: String,
/// Headless service for k8s DNS discovery.
#[serde(default)]
pub headless_service: Option<String>,
/// Static bootstrap peers ("endpointid@host:port").
#[serde(default)]
pub bootstrap_peers: Option<Vec<String>>,
}
impl Default for DiscoveryConfig {
fn default() -> Self {
Self {
method: default_discovery_method(),
headless_service: None,
bootstrap_peers: None,
}
}
}
fn default_discovery_method() -> String { "k8s".to_string() }
#[derive(Debug, Deserialize, Clone)]
pub struct BandwidthClusterConfig {
#[serde(default = "default_broadcast_interval")]
pub broadcast_interval_secs: u64,
#[serde(default = "default_stale_peer_timeout")]
pub stale_peer_timeout_secs: u64,
/// Sliding window size for aggregate bandwidth rate calculation.
#[serde(default = "default_meter_window")]
pub meter_window_secs: u64,
}
fn default_meter_window() -> u64 { 30 }
fn default_broadcast_interval() -> u64 { 1 }
fn default_stale_peer_timeout() -> u64 { 30 }
#[derive(Debug, Deserialize, Clone)]
pub struct ModelsConfig {
#[serde(default = "default_model_dir")]
pub model_dir: String,
#[serde(default = "default_max_model_size")]
pub max_model_size_bytes: u64,
#[serde(default = "default_chunk_size")]
pub chunk_size: u32,
}
fn default_model_dir() -> String { "/models".to_string() }
fn default_max_model_size() -> u64 { 52_428_800 } // 50MB
fn default_chunk_size() -> u32 { 65_536 } // 64KB
impl Config {
pub fn load(path: &str) -> Result<Self> {
let raw = fs::read_to_string(path)