mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-04-01 00:33:40 +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 {
|
impl RegistrationSnapshot {
|
||||||
|
/// Creates a stable registration snapshot sorted by node identifier.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(mut registrations: Vec<NodeRegistration>) -> Self {
|
pub fn new(mut registrations: Vec<NodeRegistration>) -> Self {
|
||||||
registrations.sort_by(|left, right| left.identifier.cmp(&right.identifier));
|
registrations.sort_by(|left, right| left.identifier.cmp(&right.identifier));
|
||||||
@ -15,21 +16,25 @@ impl RegistrationSnapshot {
|
|||||||
Self { registrations }
|
Self { registrations }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of registrations in the snapshot.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.registrations.len()
|
self.registrations.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` when the snapshot contains no registrations.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.registrations.is_empty()
|
self.registrations.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates registrations in deterministic identifier order.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &NodeRegistration> {
|
pub fn iter(&self) -> impl Iterator<Item = &NodeRegistration> {
|
||||||
self.registrations.iter()
|
self.registrations.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Looks up a registration by its stable node identifier.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&self, identifier: &str) -> Option<&NodeRegistration> {
|
pub fn get(&self, identifier: &str) -> Option<&NodeRegistration> {
|
||||||
self.registrations
|
self.registrations
|
||||||
|
|||||||
@ -2,15 +2,21 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::NodeArtifactFile;
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct NodeArtifactsBundle {
|
pub struct NodeArtifactsBundle {
|
||||||
|
/// Per-node artifact entries keyed by identifier.
|
||||||
pub nodes: Vec<NodeArtifactsBundleEntry>,
|
pub nodes: Vec<NodeArtifactsBundleEntry>,
|
||||||
|
/// Files that should be served alongside every node-specific entry.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub shared_files: Vec<NodeArtifactFile>,
|
pub shared_files: Vec<NodeArtifactFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeArtifactsBundle {
|
impl NodeArtifactsBundle {
|
||||||
|
/// Creates a bundle with node-specific entries only.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(nodes: Vec<NodeArtifactsBundleEntry>) -> Self {
|
pub fn new(nodes: Vec<NodeArtifactsBundleEntry>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -19,6 +25,7 @@ impl NodeArtifactsBundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attaches files that should be served alongside every node entry.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_shared_files(mut self, shared_files: Vec<NodeArtifactFile>) -> Self {
|
pub fn with_shared_files(mut self, shared_files: Vec<NodeArtifactFile>) -> Self {
|
||||||
self.shared_files = shared_files;
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct NodeArtifactsBundleEntry {
|
pub struct NodeArtifactsBundleEntry {
|
||||||
/// Stable node identifier used by cfgsync lookup.
|
/// Stable node identifier used by cfgsync lookup.
|
||||||
|
|||||||
@ -18,10 +18,14 @@ pub enum ClientError {
|
|||||||
Decode(serde_json::Error),
|
Decode(serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Result of probing cfgsync for a node's current artifact availability.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ConfigFetchStatus {
|
pub enum ConfigFetchStatus {
|
||||||
|
/// The node payload is ready and can be fetched successfully.
|
||||||
Ready,
|
Ready,
|
||||||
|
/// The node has registered but artifacts are not ready yet.
|
||||||
NotReady,
|
NotReady,
|
||||||
|
/// The server does not know how to materialize artifacts for this node.
|
||||||
Missing,
|
Missing,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +37,7 @@ pub struct CfgsyncClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CfgsyncClient {
|
impl CfgsyncClient {
|
||||||
|
/// Creates a cfgsync client pointed at the given server base URL.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(base_url: impl Into<String>) -> Self {
|
pub fn new(base_url: impl Into<String>) -> Self {
|
||||||
let mut base_url = base_url.into();
|
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]
|
#[must_use]
|
||||||
pub fn base_url(&self) -> &str {
|
pub fn base_url(&self) -> &str {
|
||||||
&self.base_url
|
&self.base_url
|
||||||
@ -63,6 +69,8 @@ impl CfgsyncClient {
|
|||||||
self.post_json("/node", payload).await
|
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(
|
pub async fn fetch_node_config_status(
|
||||||
&self,
|
&self,
|
||||||
payload: &NodeRegistration,
|
payload: &NodeRegistration,
|
||||||
|
|||||||
@ -110,8 +110,11 @@ impl<'de> Deserialize<'de> for RegistrationPayload {
|
|||||||
/// Node metadata recorded before config materialization.
|
/// Node metadata recorded before config materialization.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct NodeRegistration {
|
pub struct NodeRegistration {
|
||||||
|
/// Stable node identifier used for registration and artifact lookup.
|
||||||
pub identifier: String,
|
pub identifier: String,
|
||||||
|
/// IPv4 address advertised as part of registration.
|
||||||
pub ip: Ipv4Addr,
|
pub ip: Ipv4Addr,
|
||||||
|
/// Adapter-owned payload interpreted only by the app materializer.
|
||||||
#[serde(default, skip_serializing_if = "RegistrationPayload::is_empty")]
|
#[serde(default, skip_serializing_if = "RegistrationPayload::is_empty")]
|
||||||
pub metadata: RegistrationPayload,
|
pub metadata: RegistrationPayload,
|
||||||
}
|
}
|
||||||
@ -170,8 +173,11 @@ impl NodeArtifactsPayload {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum CfgsyncErrorCode {
|
pub enum CfgsyncErrorCode {
|
||||||
|
/// No artifact payload is available for the requested node.
|
||||||
MissingConfig,
|
MissingConfig,
|
||||||
|
/// The node is registered but artifacts are not ready yet.
|
||||||
NotReady,
|
NotReady,
|
||||||
|
/// An unexpected server-side failure occurred.
|
||||||
Internal,
|
Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +185,9 @@ pub enum CfgsyncErrorCode {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Error)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Error)]
|
||||||
#[error("{code:?}: {message}")]
|
#[error("{code:?}: {message}")]
|
||||||
pub struct CfgsyncErrorResponse {
|
pub struct CfgsyncErrorResponse {
|
||||||
|
/// Machine-readable failure category.
|
||||||
pub code: CfgsyncErrorCode,
|
pub code: CfgsyncErrorCode,
|
||||||
|
/// Human-readable error details.
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,13 +222,17 @@ impl CfgsyncErrorResponse {
|
|||||||
|
|
||||||
/// Resolution outcome for a requested node identifier.
|
/// Resolution outcome for a requested node identifier.
|
||||||
pub enum ConfigResolveResponse {
|
pub enum ConfigResolveResponse {
|
||||||
|
/// Artifacts are ready for the requested node.
|
||||||
Config(NodeArtifactsPayload),
|
Config(NodeArtifactsPayload),
|
||||||
|
/// Artifacts could not be resolved for the requested node.
|
||||||
Error(CfgsyncErrorResponse),
|
Error(CfgsyncErrorResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Outcome for a node registration request.
|
/// Outcome for a node registration request.
|
||||||
pub enum RegisterNodeResponse {
|
pub enum RegisterNodeResponse {
|
||||||
|
/// Registration was accepted.
|
||||||
Registered,
|
Registered,
|
||||||
|
/// Registration failed.
|
||||||
Error(CfgsyncErrorResponse),
|
Error(CfgsyncErrorResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,9 @@ pub struct RenderedCfgsync {
|
|||||||
/// Output paths used when materializing rendered cfgsync files.
|
/// Output paths used when materializing rendered cfgsync files.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct CfgsyncOutputPaths<'a> {
|
pub struct CfgsyncOutputPaths<'a> {
|
||||||
|
/// Output path for the rendered server config YAML.
|
||||||
pub config_path: &'a Path,
|
pub config_path: &'a Path,
|
||||||
|
/// Output path for the rendered static bundle YAML.
|
||||||
pub bundle_path: &'a Path,
|
pub bundle_path: &'a Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,10 +57,15 @@ pub fn write_rendered_cfgsync(
|
|||||||
/// Optional overrides applied to a cfgsync template document.
|
/// Optional overrides applied to a cfgsync template document.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct CfgsyncConfigOverrides {
|
pub struct CfgsyncConfigOverrides {
|
||||||
|
/// Override for the HTTP listen port.
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
|
/// Override for the expected initial host count.
|
||||||
pub n_hosts: Option<usize>,
|
pub n_hosts: Option<usize>,
|
||||||
|
/// Minimum timeout to enforce on the rendered template.
|
||||||
pub timeout_floor_secs: Option<u64>,
|
pub timeout_floor_secs: Option<u64>,
|
||||||
|
/// Override for the bundle path written into cfgsync config.
|
||||||
pub bundle_path: Option<String>,
|
pub bundle_path: Option<String>,
|
||||||
|
/// Optional OTLP metrics endpoint injected into tracing settings.
|
||||||
pub metrics_otlp_ingest_url: Option<String>,
|
pub metrics_otlp_ingest_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ pub struct CfgsyncServerState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CfgsyncServerState {
|
impl CfgsyncServerState {
|
||||||
|
/// Wraps a node config source for use by cfgsync HTTP handlers.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(repo: Arc<dyn NodeConfigSource>) -> Self {
|
pub fn new(repo: Arc<dyn NodeConfigSource>) -> Self {
|
||||||
Self { repo }
|
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 {
|
pub fn build_cfgsync_router(state: CfgsyncServerState) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/register", post(register_node))
|
.route("/register", post(register_node))
|
||||||
@ -91,6 +94,7 @@ pub fn build_cfgsync_router(state: CfgsyncServerState) -> Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
/// Builds the legacy cfgsync router that still serves `/init-with-node`.
|
||||||
pub fn build_legacy_cfgsync_router(state: CfgsyncServerState) -> Router {
|
pub fn build_legacy_cfgsync_router(state: CfgsyncServerState) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/register", post(register_node))
|
.route("/register", post(register_node))
|
||||||
|
|||||||
@ -9,8 +9,10 @@ use crate::{
|
|||||||
|
|
||||||
/// Source of cfgsync node payloads.
|
/// Source of cfgsync node payloads.
|
||||||
pub trait NodeConfigSource: Send + Sync {
|
pub trait NodeConfigSource: Send + Sync {
|
||||||
|
/// Records a node registration before config resolution.
|
||||||
fn register(&self, registration: NodeRegistration) -> RegisterNodeResponse;
|
fn register(&self, registration: NodeRegistration) -> RegisterNodeResponse;
|
||||||
|
|
||||||
|
/// Resolves the current artifact payload for a previously registered node.
|
||||||
fn resolve(&self, registration: &NodeRegistration) -> ConfigResolveResponse;
|
fn resolve(&self, registration: &NodeRegistration) -> ConfigResolveResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,11 +22,13 @@ pub struct StaticConfigSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StaticConfigSource {
|
impl StaticConfigSource {
|
||||||
|
/// Builds an in-memory source from fully formed payloads.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_payloads(configs: HashMap<String, NodeArtifactsPayload>) -> Arc<Self> {
|
pub fn from_payloads(configs: HashMap<String, NodeArtifactsPayload>) -> Arc<Self> {
|
||||||
Arc::new(Self { configs })
|
Arc::new(Self { configs })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds an in-memory source from a static bundle document.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_bundle(bundle: NodeArtifactsBundle) -> Arc<Self> {
|
pub fn from_bundle(bundle: NodeArtifactsBundle) -> Arc<Self> {
|
||||||
Self::from_payloads(bundle_to_payload_map(bundle))
|
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]
|
#[must_use]
|
||||||
pub fn bundle_to_payload_map(bundle: NodeArtifactsBundle) -> HashMap<String, NodeArtifactsPayload> {
|
pub fn bundle_to_payload_map(bundle: NodeArtifactsBundle) -> HashMap<String, NodeArtifactsPayload> {
|
||||||
let shared_files = bundle.shared_files;
|
let shared_files = bundle.shared_files;
|
||||||
@ -91,6 +96,7 @@ pub fn bundle_to_payload_map(bundle: NodeArtifactsBundle) -> HashMap<String, Nod
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads a cfgsync bundle YAML file from disk.
|
||||||
pub fn load_bundle(path: &Path) -> Result<NodeArtifactsBundle, BundleLoadError> {
|
pub fn load_bundle(path: &Path) -> Result<NodeArtifactsBundle, BundleLoadError> {
|
||||||
let path_string = path.display().to_string();
|
let path_string = path.display().to_string();
|
||||||
let raw = fs::read_to_string(path).map_err(|source| BundleLoadError::ReadBundle {
|
let raw = fs::read_to_string(path).map_err(|source| BundleLoadError::ReadBundle {
|
||||||
|
|||||||
@ -24,11 +24,13 @@ pub struct ArtifactOutputMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ArtifactOutputMap {
|
impl ArtifactOutputMap {
|
||||||
|
/// Creates an empty artifact output map.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Routes one artifact path from the payload to a local output path.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn route(
|
pub fn route(
|
||||||
mut self,
|
mut self,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use thiserror::Error;
|
|||||||
/// Runtime cfgsync server config loaded from YAML.
|
/// Runtime cfgsync server config loaded from YAML.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct CfgsyncServerConfig {
|
pub struct CfgsyncServerConfig {
|
||||||
|
/// HTTP port to bind the cfgsync server on.
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
/// Source used by the runtime-managed cfgsync server.
|
/// Source used by the runtime-managed cfgsync server.
|
||||||
pub source: CfgsyncServerSource,
|
pub source: CfgsyncServerSource,
|
||||||
@ -31,7 +32,9 @@ pub struct CfgsyncServerConfig {
|
|||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||||
pub enum CfgsyncServerSource {
|
pub enum CfgsyncServerSource {
|
||||||
|
/// Serve a static precomputed artifact bundle directly.
|
||||||
Bundle { bundle_path: String },
|
Bundle { bundle_path: String },
|
||||||
|
/// Require node registration before serving artifacts from a static bundle.
|
||||||
RegistrationBundle { bundle_path: String },
|
RegistrationBundle { bundle_path: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +103,8 @@ impl CfgsyncServerConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a config that serves a static bundle behind the registration
|
||||||
|
/// flow.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn for_registration_bundle(port: u16, bundle_path: impl Into<String>) -> Self {
|
pub fn for_registration_bundle(port: u16, bundle_path: impl Into<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user