From fd154a948789dbf1968236fb53e1ff314befbe3a Mon Sep 17 00:00:00 2001 From: andrussal Date: Thu, 12 Mar 2026 07:35:22 +0100 Subject: [PATCH] Expand cfgsync rustdoc coverage further --- cfgsync/adapter/src/registrations.rs | 5 +++++ cfgsync/core/src/bundle.rs | 11 +++++++++-- cfgsync/core/src/client.rs | 8 ++++++++ cfgsync/core/src/protocol.rs | 12 ++++++++++++ cfgsync/core/src/render.rs | 7 +++++++ cfgsync/core/src/server.rs | 4 ++++ cfgsync/core/src/source.rs | 6 ++++++ cfgsync/runtime/src/client.rs | 2 ++ cfgsync/runtime/src/server.rs | 5 +++++ 9 files changed, 58 insertions(+), 2 deletions(-) diff --git a/cfgsync/adapter/src/registrations.rs b/cfgsync/adapter/src/registrations.rs index 47e365f..4970a8b 100644 --- a/cfgsync/adapter/src/registrations.rs +++ b/cfgsync/adapter/src/registrations.rs @@ -8,6 +8,7 @@ pub struct RegistrationSnapshot { } impl RegistrationSnapshot { + /// Creates a stable registration snapshot sorted by node identifier. #[must_use] pub fn new(mut registrations: Vec) -> Self { registrations.sort_by(|left, right| left.identifier.cmp(&right.identifier)); @@ -15,21 +16,25 @@ impl RegistrationSnapshot { Self { registrations } } + /// Returns the number of registrations in the snapshot. #[must_use] pub fn len(&self) -> usize { self.registrations.len() } + /// Returns `true` when the snapshot contains no registrations. #[must_use] pub fn is_empty(&self) -> bool { self.registrations.is_empty() } + /// Iterates registrations in deterministic identifier order. #[must_use] pub fn iter(&self) -> impl Iterator { self.registrations.iter() } + /// Looks up a registration by its stable node identifier. #[must_use] pub fn get(&self, identifier: &str) -> Option<&NodeRegistration> { self.registrations diff --git a/cfgsync/core/src/bundle.rs b/cfgsync/core/src/bundle.rs index 31f6723..3fc5675 100644 --- a/cfgsync/core/src/bundle.rs +++ b/cfgsync/core/src/bundle.rs @@ -2,15 +2,21 @@ use serde::{Deserialize, Serialize}; use crate::NodeArtifactFile; -/// Top-level cfgsync bundle containing per-node file payloads. +/// Static cfgsync artifact bundle. +/// +/// This is the bundle-oriented source format used when all artifacts are known +/// ahead of time and no registration-time materialization is required. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NodeArtifactsBundle { + /// Per-node artifact entries keyed by identifier. pub nodes: Vec, + /// Files that should be served alongside every node-specific entry. #[serde(default)] pub shared_files: Vec, } impl NodeArtifactsBundle { + /// Creates a bundle with node-specific entries only. #[must_use] pub fn new(nodes: Vec) -> Self { Self { @@ -19,6 +25,7 @@ impl NodeArtifactsBundle { } } + /// Attaches files that should be served alongside every node entry. #[must_use] pub fn with_shared_files(mut self, shared_files: Vec) -> Self { self.shared_files = shared_files; @@ -26,7 +33,7 @@ impl NodeArtifactsBundle { } } -/// Artifact set for a single node resolved by identifier. +/// One node entry inside a static cfgsync bundle. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NodeArtifactsBundleEntry { /// Stable node identifier used by cfgsync lookup. diff --git a/cfgsync/core/src/client.rs b/cfgsync/core/src/client.rs index 4032c35..d682936 100644 --- a/cfgsync/core/src/client.rs +++ b/cfgsync/core/src/client.rs @@ -18,10 +18,14 @@ pub enum ClientError { Decode(serde_json::Error), } +/// Result of probing cfgsync for a node's current artifact availability. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ConfigFetchStatus { + /// The node payload is ready and can be fetched successfully. Ready, + /// The node has registered but artifacts are not ready yet. NotReady, + /// The server does not know how to materialize artifacts for this node. Missing, } @@ -33,6 +37,7 @@ pub struct CfgsyncClient { } impl CfgsyncClient { + /// Creates a cfgsync client pointed at the given server base URL. #[must_use] pub fn new(base_url: impl Into) -> Self { let mut base_url = base_url.into(); @@ -45,6 +50,7 @@ impl CfgsyncClient { } } + /// Returns the normalized cfgsync server base URL used for requests. #[must_use] pub fn base_url(&self) -> &str { &self.base_url @@ -63,6 +69,8 @@ impl CfgsyncClient { self.post_json("/node", payload).await } + /// Probes whether artifacts for a node are ready, missing, or still + /// pending. pub async fn fetch_node_config_status( &self, payload: &NodeRegistration, diff --git a/cfgsync/core/src/protocol.rs b/cfgsync/core/src/protocol.rs index f794fd1..1bba7d7 100644 --- a/cfgsync/core/src/protocol.rs +++ b/cfgsync/core/src/protocol.rs @@ -110,8 +110,11 @@ impl<'de> Deserialize<'de> for RegistrationPayload { /// Node metadata recorded before config materialization. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct NodeRegistration { + /// Stable node identifier used for registration and artifact lookup. pub identifier: String, + /// IPv4 address advertised as part of registration. pub ip: Ipv4Addr, + /// Adapter-owned payload interpreted only by the app materializer. #[serde(default, skip_serializing_if = "RegistrationPayload::is_empty")] pub metadata: RegistrationPayload, } @@ -170,8 +173,11 @@ impl NodeArtifactsPayload { #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum CfgsyncErrorCode { + /// No artifact payload is available for the requested node. MissingConfig, + /// The node is registered but artifacts are not ready yet. NotReady, + /// An unexpected server-side failure occurred. Internal, } @@ -179,7 +185,9 @@ pub enum CfgsyncErrorCode { #[derive(Debug, Clone, Serialize, Deserialize, Error)] #[error("{code:?}: {message}")] pub struct CfgsyncErrorResponse { + /// Machine-readable failure category. pub code: CfgsyncErrorCode, + /// Human-readable error details. pub message: String, } @@ -214,13 +222,17 @@ impl CfgsyncErrorResponse { /// Resolution outcome for a requested node identifier. pub enum ConfigResolveResponse { + /// Artifacts are ready for the requested node. Config(NodeArtifactsPayload), + /// Artifacts could not be resolved for the requested node. Error(CfgsyncErrorResponse), } /// Outcome for a node registration request. pub enum RegisterNodeResponse { + /// Registration was accepted. Registered, + /// Registration failed. Error(CfgsyncErrorResponse), } diff --git a/cfgsync/core/src/render.rs b/cfgsync/core/src/render.rs index 2031986..b963a99 100644 --- a/cfgsync/core/src/render.rs +++ b/cfgsync/core/src/render.rs @@ -16,7 +16,9 @@ pub struct RenderedCfgsync { /// Output paths used when materializing rendered cfgsync files. #[derive(Debug, Clone, Copy)] pub struct CfgsyncOutputPaths<'a> { + /// Output path for the rendered server config YAML. pub config_path: &'a Path, + /// Output path for the rendered static bundle YAML. pub bundle_path: &'a Path, } @@ -55,10 +57,15 @@ pub fn write_rendered_cfgsync( /// Optional overrides applied to a cfgsync template document. #[derive(Debug, Clone, Default)] pub struct CfgsyncConfigOverrides { + /// Override for the HTTP listen port. pub port: Option, + /// Override for the expected initial host count. pub n_hosts: Option, + /// Minimum timeout to enforce on the rendered template. pub timeout_floor_secs: Option, + /// Override for the bundle path written into cfgsync config. pub bundle_path: Option, + /// Optional OTLP metrics endpoint injected into tracing settings. pub metrics_otlp_ingest_url: Option, } diff --git a/cfgsync/core/src/server.rs b/cfgsync/core/src/server.rs index 3a82a17..925e997 100644 --- a/cfgsync/core/src/server.rs +++ b/cfgsync/core/src/server.rs @@ -14,6 +14,7 @@ pub struct CfgsyncServerState { } impl CfgsyncServerState { + /// Wraps a node config source for use by cfgsync HTTP handlers. #[must_use] pub fn new(repo: Arc) -> Self { Self { repo } @@ -83,6 +84,8 @@ fn error_status(code: &CfgsyncErrorCode) -> StatusCode { } } +/// Builds the primary cfgsync router with registration and node artifact +/// routes. pub fn build_cfgsync_router(state: CfgsyncServerState) -> Router { Router::new() .route("/register", post(register_node)) @@ -91,6 +94,7 @@ pub fn build_cfgsync_router(state: CfgsyncServerState) -> Router { } #[doc(hidden)] +/// Builds the legacy cfgsync router that still serves `/init-with-node`. pub fn build_legacy_cfgsync_router(state: CfgsyncServerState) -> Router { Router::new() .route("/register", post(register_node)) diff --git a/cfgsync/core/src/source.rs b/cfgsync/core/src/source.rs index 9d00d9e..2cdf513 100644 --- a/cfgsync/core/src/source.rs +++ b/cfgsync/core/src/source.rs @@ -9,8 +9,10 @@ use crate::{ /// Source of cfgsync node payloads. pub trait NodeConfigSource: Send + Sync { + /// Records a node registration before config resolution. fn register(&self, registration: NodeRegistration) -> RegisterNodeResponse; + /// Resolves the current artifact payload for a previously registered node. fn resolve(&self, registration: &NodeRegistration) -> ConfigResolveResponse; } @@ -20,11 +22,13 @@ pub struct StaticConfigSource { } impl StaticConfigSource { + /// Builds an in-memory source from fully formed payloads. #[must_use] pub fn from_payloads(configs: HashMap) -> Arc { Arc::new(Self { configs }) } + /// Builds an in-memory source from a static bundle document. #[must_use] pub fn from_bundle(bundle: NodeArtifactsBundle) -> Arc { Self::from_payloads(bundle_to_payload_map(bundle)) @@ -73,6 +77,7 @@ pub enum BundleLoadError { }, } +/// Converts a static bundle into the node payload map used by static sources. #[must_use] pub fn bundle_to_payload_map(bundle: NodeArtifactsBundle) -> HashMap { let shared_files = bundle.shared_files; @@ -91,6 +96,7 @@ pub fn bundle_to_payload_map(bundle: NodeArtifactsBundle) -> HashMap Result { let path_string = path.display().to_string(); let raw = fs::read_to_string(path).map_err(|source| BundleLoadError::ReadBundle { diff --git a/cfgsync/runtime/src/client.rs b/cfgsync/runtime/src/client.rs index b693ad9..510da04 100644 --- a/cfgsync/runtime/src/client.rs +++ b/cfgsync/runtime/src/client.rs @@ -24,11 +24,13 @@ pub struct ArtifactOutputMap { } impl ArtifactOutputMap { + /// Creates an empty artifact output map. #[must_use] pub fn new() -> Self { Self::default() } + /// Routes one artifact path from the payload to a local output path. #[must_use] pub fn route( mut self, diff --git a/cfgsync/runtime/src/server.rs b/cfgsync/runtime/src/server.rs index 0e00628..9f788d4 100644 --- a/cfgsync/runtime/src/server.rs +++ b/cfgsync/runtime/src/server.rs @@ -16,6 +16,7 @@ use thiserror::Error; /// Runtime cfgsync server config loaded from YAML. #[derive(Debug, Clone, PartialEq, Eq)] pub struct CfgsyncServerConfig { + /// HTTP port to bind the cfgsync server on. pub port: u16, /// Source used by the runtime-managed cfgsync server. pub source: CfgsyncServerSource, @@ -31,7 +32,9 @@ pub struct CfgsyncServerConfig { #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] #[serde(tag = "kind", rename_all = "snake_case")] pub enum CfgsyncServerSource { + /// Serve a static precomputed artifact bundle directly. Bundle { bundle_path: String }, + /// Require node registration before serving artifacts from a static bundle. RegistrationBundle { bundle_path: String }, } @@ -100,6 +103,8 @@ impl CfgsyncServerConfig { } } + /// Builds a config that serves a static bundle behind the registration + /// flow. #[must_use] pub fn for_registration_bundle(port: u16, bundle_path: impl Into) -> Self { Self {