mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-03-31 16:23:08 +00:00
Expand cfgsync rustdoc coverage further
This commit is contained in:
parent
b90734483b
commit
fd154a9487
@ -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<NodeRegistration>) -> 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<Item = &NodeRegistration> {
|
||||
self.registrations.iter()
|
||||
}
|
||||
|
||||
/// Looks up a registration by its stable node identifier.
|
||||
#[must_use]
|
||||
pub fn get(&self, identifier: &str) -> Option<&NodeRegistration> {
|
||||
self.registrations
|
||||
|
||||
@ -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<NodeArtifactsBundleEntry>,
|
||||
/// Files that should be served alongside every node-specific entry.
|
||||
#[serde(default)]
|
||||
pub shared_files: Vec<NodeArtifactFile>,
|
||||
}
|
||||
|
||||
impl NodeArtifactsBundle {
|
||||
/// Creates a bundle with node-specific entries only.
|
||||
#[must_use]
|
||||
pub fn new(nodes: Vec<NodeArtifactsBundleEntry>) -> 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<NodeArtifactFile>) -> 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.
|
||||
|
||||
@ -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<String>) -> 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,
|
||||
|
||||
@ -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),
|
||||
}
|
||||
|
||||
|
||||
@ -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<u16>,
|
||||
/// Override for the expected initial host count.
|
||||
pub n_hosts: Option<usize>,
|
||||
/// Minimum timeout to enforce on the rendered template.
|
||||
pub timeout_floor_secs: Option<u64>,
|
||||
/// Override for the bundle path written into cfgsync config.
|
||||
pub bundle_path: Option<String>,
|
||||
/// Optional OTLP metrics endpoint injected into tracing settings.
|
||||
pub metrics_otlp_ingest_url: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
@ -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<dyn NodeConfigSource>) -> 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))
|
||||
|
||||
@ -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<String, NodeArtifactsPayload>) -> Arc<Self> {
|
||||
Arc::new(Self { configs })
|
||||
}
|
||||
|
||||
/// Builds an in-memory source from a static bundle document.
|
||||
#[must_use]
|
||||
pub fn from_bundle(bundle: NodeArtifactsBundle) -> Arc<Self> {
|
||||
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<String, NodeArtifactsPayload> {
|
||||
let shared_files = bundle.shared_files;
|
||||
@ -91,6 +96,7 @@ pub fn bundle_to_payload_map(bundle: NodeArtifactsBundle) -> HashMap<String, Nod
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Loads a cfgsync bundle YAML file from disk.
|
||||
pub fn load_bundle(path: &Path) -> Result<NodeArtifactsBundle, BundleLoadError> {
|
||||
let path_string = path.display().to_string();
|
||||
let raw = fs::read_to_string(path).map_err(|source| BundleLoadError::ReadBundle {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<String>) -> Self {
|
||||
Self {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user