From a751d819ea24fdea4ac81b46f1ee3d0b3c393aa3 Mon Sep 17 00:00:00 2001 From: andrussal Date: Tue, 10 Mar 2026 10:56:42 +0100 Subject: [PATCH] Polish cfgsync adapter naming for external use --- cfgsync/adapter/src/lib.rs | 175 +++++++++++++++++++++------------- cfgsync/runtime/src/server.rs | 10 +- 2 files changed, 116 insertions(+), 69 deletions(-) diff --git a/cfgsync/adapter/src/lib.rs b/cfgsync/adapter/src/lib.rs index f5b24d5..2725d13 100644 --- a/cfgsync/adapter/src/lib.rs +++ b/cfgsync/adapter/src/lib.rs @@ -11,28 +11,28 @@ use thiserror::Error; /// Type-erased cfgsync adapter error used to preserve source context. pub type DynCfgsyncError = Box; -/// Per-node rendered config output used to build cfgsync bundles. +/// Per-node artifact payload served by cfgsync for one registered node. #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CfgsyncNodeConfig { +pub struct NodeArtifacts { /// Stable node identifier resolved by the adapter. pub identifier: String, /// Files served to the node after cfgsync registration. pub files: Vec, } -/// Node artifacts produced by a cfgsync materializer. +/// Materialized artifact files for a single registered node. #[derive(Debug, Clone, Default)] -pub struct CfgsyncNodeArtifacts { +pub struct ArtifactSet { files: Vec, } /// Immutable view of registrations currently known to cfgsync. #[derive(Debug, Clone, Default)] -pub struct RegistrationSnapshot { +pub struct RegistrationSet { registrations: Vec, } -impl RegistrationSnapshot { +impl RegistrationSet { #[must_use] pub fn new(registrations: Vec) -> Self { Self { registrations } @@ -61,7 +61,7 @@ impl RegistrationSnapshot { } } -impl CfgsyncNodeArtifacts { +impl ArtifactSet { #[must_use] pub fn new(files: Vec) -> Self { Self { files } @@ -78,15 +78,15 @@ impl CfgsyncNodeArtifacts { } } -/// Precomputed node configs indexed by stable identifier. +/// Artifact payloads indexed by stable node identifier. #[derive(Debug, Clone, Default)] -pub struct CfgsyncNodeCatalog { - nodes: HashMap, +pub struct NodeArtifactsCatalog { + nodes: HashMap, } -impl CfgsyncNodeCatalog { +impl NodeArtifactsCatalog { #[must_use] - pub fn new(nodes: Vec) -> Self { + pub fn new(nodes: Vec) -> Self { let nodes = nodes .into_iter() .map(|node| (node.identifier.clone(), node)) @@ -96,7 +96,7 @@ impl CfgsyncNodeCatalog { } #[must_use] - pub fn resolve(&self, identifier: &str) -> Option<&CfgsyncNodeConfig> { + pub fn resolve(&self, identifier: &str) -> Option<&NodeArtifacts> { self.nodes.get(identifier) } @@ -111,35 +111,51 @@ impl CfgsyncNodeCatalog { } #[must_use] - pub fn into_configs(self) -> Vec { + pub fn into_nodes(self) -> Vec { self.nodes.into_values().collect() } + + #[doc(hidden)] + #[must_use] + pub fn into_configs(self) -> Vec { + self.into_nodes() + } } -/// Adapter-side node config materialization contract used by cfgsync server. -pub trait CfgsyncMaterializer: Send + Sync { +/// Adapter-side materialization contract for a single registered node. +pub trait NodeArtifactsMaterializer: Send + Sync { fn materialize( &self, registration: &NodeRegistration, - registrations: &RegistrationSnapshot, - ) -> Result, DynCfgsyncError>; + registrations: &RegistrationSet, + ) -> Result, DynCfgsyncError>; } -/// Adapter contract for materializing a whole registration snapshot into +/// Backward-compatible alias for the previous materializer trait name. +pub trait CfgsyncMaterializer: NodeArtifactsMaterializer {} + +impl CfgsyncMaterializer for T where T: NodeArtifactsMaterializer + ?Sized {} + +/// Adapter contract for materializing a whole registration set into /// per-node cfgsync artifacts. -pub trait CfgsyncSnapshotMaterializer: Send + Sync { +pub trait RegistrationSetMaterializer: Send + Sync { fn materialize_snapshot( &self, - registrations: &RegistrationSnapshot, - ) -> Result, DynCfgsyncError>; + registrations: &RegistrationSet, + ) -> Result, DynCfgsyncError>; } -impl CfgsyncMaterializer for CfgsyncNodeCatalog { +/// Backward-compatible alias for the previous snapshot materializer trait name. +pub trait CfgsyncSnapshotMaterializer: RegistrationSetMaterializer {} + +impl CfgsyncSnapshotMaterializer for T where T: RegistrationSetMaterializer + ?Sized {} + +impl NodeArtifactsMaterializer for NodeArtifactsCatalog { fn materialize( &self, registration: &NodeRegistration, - _registrations: &RegistrationSnapshot, - ) -> Result, DynCfgsyncError> { + _registrations: &RegistrationSet, + ) -> Result, DynCfgsyncError> { let artifacts = self .resolve(®istration.identifier) .map(build_node_artifacts_from_config); @@ -148,22 +164,22 @@ impl CfgsyncMaterializer for CfgsyncNodeCatalog { } } -impl CfgsyncSnapshotMaterializer for CfgsyncNodeCatalog { +impl RegistrationSetMaterializer for NodeArtifactsCatalog { fn materialize_snapshot( &self, - _registrations: &RegistrationSnapshot, - ) -> Result, DynCfgsyncError> { + _registrations: &RegistrationSet, + ) -> Result, DynCfgsyncError> { Ok(Some(self.clone())) } } /// Registration-aware provider backed by an adapter materializer. -pub struct MaterializingConfigProvider { +pub struct RegistrationConfigProvider { materializer: M, registrations: Mutex>, } -impl MaterializingConfigProvider { +impl RegistrationConfigProvider { #[must_use] pub fn new(materializer: M) -> Self { Self { @@ -181,23 +197,23 @@ impl MaterializingConfigProvider { registrations.get(identifier).cloned() } - fn registration_snapshot(&self) -> RegistrationSnapshot { + fn registration_set(&self) -> RegistrationSet { let registrations = self .registrations .lock() .expect("cfgsync registration store should not be poisoned"); - RegistrationSnapshot::new(registrations.values().cloned().collect()) + RegistrationSet::new(registrations.values().cloned().collect()) } } /// Registration-aware provider backed by a snapshot materializer. -pub struct SnapshotMaterializingConfigProvider { +pub struct SnapshotConfigProvider { materializer: M, registrations: Mutex>, } -impl SnapshotMaterializingConfigProvider { +impl SnapshotConfigProvider { #[must_use] pub fn new(materializer: M) -> Self { Self { @@ -215,19 +231,19 @@ impl SnapshotMaterializingConfigProvider { registrations.get(identifier).cloned() } - fn registration_snapshot(&self) -> RegistrationSnapshot { + fn registration_set(&self) -> RegistrationSet { let registrations = self .registrations .lock() .expect("cfgsync registration store should not be poisoned"); - RegistrationSnapshot::new(registrations.values().cloned().collect()) + RegistrationSet::new(registrations.values().cloned().collect()) } } -impl ConfigProvider for SnapshotMaterializingConfigProvider +impl ConfigProvider for SnapshotConfigProvider where - M: CfgsyncSnapshotMaterializer, + M: RegistrationSetMaterializer, { fn register(&self, registration: NodeRegistration) -> RegistrationResponse { let mut registrations = self @@ -249,7 +265,7 @@ where } }; - let registrations = self.registration_snapshot(); + let registrations = self.registration_set(); let catalog = match self.materializer.materialize_snapshot(®istrations) { Ok(Some(catalog)) => catalog, Ok(None) => { @@ -273,9 +289,9 @@ where } } -impl ConfigProvider for MaterializingConfigProvider +impl ConfigProvider for RegistrationConfigProvider where - M: CfgsyncMaterializer, + M: NodeArtifactsMaterializer, { fn register(&self, registration: NodeRegistration) -> RegistrationResponse { let mut registrations = self @@ -296,7 +312,7 @@ where )); } }; - let registrations = self.registration_snapshot(); + let registrations = self.registration_set(); match self.materializer.materialize(®istration, ®istrations) { Ok(Some(artifacts)) => { @@ -340,6 +356,11 @@ pub trait CfgsyncEnv { fn serialize_node_config(config: &Self::NodeConfig) -> Result; } +/// Preferred public name for application-side cfgsync integration. +pub trait DeploymentAdapter: CfgsyncEnv {} + +impl DeploymentAdapter for T where T: CfgsyncEnv + ?Sized {} + /// High-level failures while building adapter output for cfgsync. #[derive(Debug, Error)] pub enum BuildCfgsyncNodesError { @@ -370,14 +391,14 @@ pub fn build_cfgsync_node_configs( deployment: &E::Deployment, hostnames: &[String], ) -> Result, BuildCfgsyncNodesError> { - Ok(build_cfgsync_node_catalog::(deployment, hostnames)?.into_configs()) + Ok(build_node_artifact_catalog::(deployment, hostnames)?.into_nodes()) } /// Builds cfgsync node configs and indexes them by stable identifier. -pub fn build_cfgsync_node_catalog( +pub fn build_node_artifact_catalog( deployment: &E::Deployment, hostnames: &[String], -) -> Result { +) -> Result { let nodes = E::nodes(deployment); ensure_hostname_count(nodes.len(), hostnames.len())?; @@ -386,7 +407,15 @@ pub fn build_cfgsync_node_catalog( output.push(build_node_entry::(deployment, node, index, hostnames)?); } - Ok(CfgsyncNodeCatalog::new(output)) + Ok(NodeArtifactsCatalog::new(output)) +} + +#[doc(hidden)] +pub fn build_cfgsync_node_catalog( + deployment: &E::Deployment, + hostnames: &[String], +) -> Result { + build_node_artifact_catalog::(deployment, hostnames) } fn ensure_hostname_count(nodes: usize, hostnames: usize) -> Result<(), BuildCfgsyncNodesError> { @@ -397,22 +426,22 @@ fn ensure_hostname_count(nodes: usize, hostnames: usize) -> Result<(), BuildCfgs Ok(()) } -fn build_node_entry( +fn build_node_entry( deployment: &E::Deployment, node: &E::Node, index: usize, hostnames: &[String], -) -> Result { +) -> Result { let node_config = build_rewritten_node_config::(deployment, node, index, hostnames)?; let config_yaml = E::serialize_node_config(&node_config).map_err(adapter_error)?; - Ok(CfgsyncNodeConfig { + Ok(NodeArtifacts { identifier: E::node_identifier(index, node), files: vec![ArtifactFile::new("/config.yaml", &config_yaml)], }) } -fn build_rewritten_node_config( +fn build_rewritten_node_config( deployment: &E::Deployment, node: &E::Node, index: usize, @@ -425,10 +454,28 @@ fn build_rewritten_node_config( Ok(node_config) } -fn build_node_artifacts_from_config(config: &CfgsyncNodeConfig) -> CfgsyncNodeArtifacts { - CfgsyncNodeArtifacts::new(config.files.clone()) +fn build_node_artifacts_from_config(config: &NodeArtifacts) -> ArtifactSet { + ArtifactSet::new(config.files.clone()) } +#[doc(hidden)] +pub type CfgsyncNodeConfig = NodeArtifacts; + +#[doc(hidden)] +pub type CfgsyncNodeArtifacts = ArtifactSet; + +#[doc(hidden)] +pub type RegistrationSnapshot = RegistrationSet; + +#[doc(hidden)] +pub type CfgsyncNodeCatalog = NodeArtifactsCatalog; + +#[doc(hidden)] +pub type MaterializingConfigProvider = RegistrationConfigProvider; + +#[doc(hidden)] +pub type SnapshotMaterializingConfigProvider = SnapshotConfigProvider; + #[cfg(test)] mod tests { use std::sync::atomic::{AtomicUsize, Ordering}; @@ -437,13 +484,13 @@ mod tests { use cfgsync_core::{CfgSyncErrorCode, ConfigProvider, NodeRegistration, RepoResponse}; use super::{ - CfgsyncMaterializer, CfgsyncNodeArtifacts, CfgsyncNodeCatalog, CfgsyncNodeConfig, - DynCfgsyncError, MaterializingConfigProvider, RegistrationSnapshot, + ArtifactSet, DynCfgsyncError, NodeArtifacts, NodeArtifactsCatalog, + NodeArtifactsMaterializer, RegistrationConfigProvider, RegistrationSet, }; #[test] fn catalog_resolves_identifier() { - let catalog = CfgsyncNodeCatalog::new(vec![CfgsyncNodeConfig { + let catalog = NodeArtifactsCatalog::new(vec![NodeArtifacts { identifier: "node-1".to_owned(), files: vec![ArtifactFile::new("/config.yaml", "key: value")], }]); @@ -455,11 +502,11 @@ mod tests { #[test] fn materializing_provider_resolves_registered_node() { - let catalog = CfgsyncNodeCatalog::new(vec![CfgsyncNodeConfig { + let catalog = NodeArtifactsCatalog::new(vec![NodeArtifacts { identifier: "node-1".to_owned(), files: vec![ArtifactFile::new("/config.yaml", "key: value")], }]); - let provider = MaterializingConfigProvider::new(catalog); + let provider = RegistrationConfigProvider::new(catalog); let registration = NodeRegistration::new("node-1", "127.0.0.1".parse().expect("parse ip")); let _ = provider.register(registration.clone()); @@ -472,11 +519,11 @@ mod tests { #[test] fn materializing_provider_reports_not_ready_before_registration() { - let catalog = CfgsyncNodeCatalog::new(vec![CfgsyncNodeConfig { + let catalog = NodeArtifactsCatalog::new(vec![NodeArtifacts { identifier: "node-1".to_owned(), files: vec![ArtifactFile::new("/config.yaml", "key: value")], }]); - let provider = MaterializingConfigProvider::new(catalog); + let provider = RegistrationConfigProvider::new(catalog); let registration = NodeRegistration::new("node-1", "127.0.0.1".parse().expect("parse ip")); match provider.resolve(®istration) { @@ -489,12 +536,12 @@ mod tests { calls: AtomicUsize, } - impl CfgsyncMaterializer for ThresholdMaterializer { + impl NodeArtifactsMaterializer for ThresholdMaterializer { fn materialize( &self, registration: &NodeRegistration, - registrations: &RegistrationSnapshot, - ) -> Result, DynCfgsyncError> { + registrations: &RegistrationSet, + ) -> Result, DynCfgsyncError> { self.calls.fetch_add(1, Ordering::SeqCst); if registrations.len() < 2 { @@ -507,13 +554,13 @@ mod tests { ArtifactFile::new("/shared.yaml", format!("peers: {peer_count}")), ]; - Ok(Some(CfgsyncNodeArtifacts::new(files))) + Ok(Some(ArtifactSet::new(files))) } } #[test] fn materializing_provider_uses_registration_snapshot_for_readiness() { - let provider = MaterializingConfigProvider::new(ThresholdMaterializer { + let provider = RegistrationConfigProvider::new(ThresholdMaterializer { calls: AtomicUsize::new(0), }); let node_a = NodeRegistration::new("node-a", "127.0.0.1".parse().expect("parse ip")); diff --git a/cfgsync/runtime/src/server.rs b/cfgsync/runtime/src/server.rs index ba987f3..16927d2 100644 --- a/cfgsync/runtime/src/server.rs +++ b/cfgsync/runtime/src/server.rs @@ -1,7 +1,7 @@ use std::{fs, path::Path, sync::Arc}; use anyhow::Context as _; -use cfgsync_adapter::{CfgsyncNodeCatalog, MaterializingConfigProvider}; +use cfgsync_adapter::{NodeArtifacts, NodeArtifactsCatalog, RegistrationConfigProvider}; use cfgsync_core::{CfgSyncBundle, CfgSyncState, ConfigProvider, FileConfigProvider, run_cfgsync}; use serde::Deserialize; @@ -35,7 +35,7 @@ fn load_bundle_provider(bundle_path: &Path) -> anyhow::Result anyhow::Result> { let bundle = load_bundle_yaml(bundle_path)?; let catalog = build_node_catalog(bundle); - let provider = MaterializingConfigProvider::new(catalog); + let provider = RegistrationConfigProvider::new(catalog); Ok(Arc::new(provider)) } @@ -48,17 +48,17 @@ fn load_bundle_yaml(bundle_path: &Path) -> anyhow::Result { .with_context(|| format!("parsing cfgsync bundle from {}", bundle_path.display())) } -fn build_node_catalog(bundle: CfgSyncBundle) -> CfgsyncNodeCatalog { +fn build_node_catalog(bundle: CfgSyncBundle) -> NodeArtifactsCatalog { let nodes = bundle .nodes .into_iter() - .map(|node| cfgsync_adapter::CfgsyncNodeConfig { + .map(|node| NodeArtifacts { identifier: node.identifier, files: node.files, }) .collect(); - CfgsyncNodeCatalog::new(nodes) + NodeArtifactsCatalog::new(nodes) } fn resolve_bundle_path(config_path: &Path, bundle_path: &str) -> std::path::PathBuf {