d_engine/config/mod.rs
1//! Configuration management module for distributed Raft consensus engine.
2//!
3//! Provides hierarchical configuration loading and validation with:
4//! - Default values as code base
5//! - Environment variable overrides
6//! - Configuration file support
7//! - Component-wise validation
8mod cluster;
9use std::fmt::Debug;
10mod monitoring;
11mod network;
12mod raft;
13mod retry;
14mod tls;
15pub use cluster::*;
16pub use monitoring::*;
17pub use network::*;
18pub use raft::*;
19pub use retry::*;
20pub use tls::*;
21
22#[cfg(test)]
23mod config_test;
24#[cfg(test)]
25mod raft_test;
26
27//---
28use std::env;
29
30use config::Config;
31use config::Environment;
32use config::File;
33use serde::Deserialize;
34use serde::Serialize;
35
36use crate::Result;
37
38/// Main configuration container for Raft consensus engine components
39///
40/// Combines all subsystem configurations with hierarchical override support:
41/// 1. Default values from code implementation
42/// 2. Configuration file specified by `CONFIG_PATH`
43/// 3. Environment variables (highest priority)
44#[derive(Serialize, Deserialize, Clone, Default)]
45pub struct RaftNodeConfig {
46 /// Cluster topology and node configuration
47 pub cluster: ClusterConfig,
48 /// Metrics and monitoring settings
49 pub monitoring: MonitoringConfig,
50 /// Network communication parameters
51 pub network: NetworkConfig,
52 /// Core Raft algorithm parameters
53 pub raft: RaftConfig,
54 /// Retry policies for distributed operations
55 pub retry: RetryPolicies,
56 /// TLS/SSL security configuration
57 pub tls: TlsConfig,
58}
59impl Debug for RaftNodeConfig {
60 fn fmt(
61 &self,
62 f: &mut std::fmt::Formatter<'_>,
63 ) -> std::fmt::Result {
64 f.debug_struct("RaftNodeConfig")
65 .field("cluster", &self.cluster)
66 .finish()
67 }
68}
69impl RaftNodeConfig {
70 /// Creates a new configuration with hierarchical override support:
71 ///
72 /// Configuration sources are merged in the following order (later sources
73 /// override earlier ones):
74 /// 1. Type defaults (lowest priority)
75 /// 2. Configuration file from `CONFIG_PATH` environment variable
76 /// 3. Environment variables with `RAFT__` prefix (highest priority)
77 ///
78 /// # Returns
79 /// Merged configuration instance or error if:
80 /// - Config file parsing fails
81 /// - Validation rules are violated
82 ///
83 /// # Example
84 /// ```ignore
85 /// // Load with default values only
86 /// let cfg = RaftNodeConfig::new()?;
87 ///
88 /// // Load with config file and environment variables
89 /// std::env::set_var("CONFIG_PATH", "config/cluster.toml");
90 /// std::env::set_var("RAFT__CLUSTER__NODE_ID", "100");
91 /// let cfg = RaftNodeConfig::new()?;
92 /// ```
93 pub fn new() -> Result<Self> {
94 // Create a basic configuration builder
95 // 1. Default values as the base layer
96 let mut builder = Config::builder().add_source(Config::try_from(&Self::default())?);
97
98 // 2. Conditionally add configuration files
99 if let Ok(config_path) = env::var("CONFIG_PATH") {
100 builder = builder.add_source(File::with_name(&config_path));
101 }
102
103 // 3. Add environment variable source
104 builder = builder.add_source(
105 Environment::with_prefix("RAFT")
106 .separator("__")
107 .ignore_empty(true)
108 .try_parsing(true),
109 );
110
111 // Build and deserialize
112 let config: Self = builder.build()?.try_deserialize()?;
113 config.validate()?;
114 Ok(config)
115 }
116
117 /// Creates a new configuration with additional overrides:
118 ///
119 /// Merging order (later sources override earlier ones):
120 /// 1. Current configuration values
121 /// 2. New configuration file
122 /// 3. Latest environment variables (highest priority)
123 ///
124 /// # Example
125 /// ```ignore
126 /// // Initial configuration
127 /// let base = RaftNodeConfig::new()?;
128 ///
129 /// // Apply runtime overrides
130 /// let final_cfg = base.with_override_config("runtime_overrides.toml")?;
131 /// ```
132 pub fn with_override_config(
133 &self,
134 path: &str,
135 ) -> Result<Self> {
136 let config: Self = Config::builder()
137 .add_source(Config::try_from(self)?) // Current config
138 .add_source(File::with_name(path)) // New overrides
139 .add_source(
140 // Fresh environment
141 Environment::with_prefix("RAFT")
142 .separator("__")
143 .ignore_empty(true)
144 .try_parsing(true),
145 )
146 .build()?
147 .try_deserialize()?;
148 config.validate()?;
149 Ok(config)
150 }
151
152 /// Validates cross-component configuration rules
153 ///
154 /// # Returns
155 /// `Ok(())` if all configurations are valid, or
156 /// `Err(Error)` containing validation failure details
157 ///
158 /// # Errors
159 /// Returns validation errors from any subsystem:
160 /// - Invalid port bindings
161 /// - Conflicting node IDs
162 /// - Expired certificates
163 /// - Retry policy conflicts
164 pub fn validate(&self) -> Result<()> {
165 self.cluster.validate()?;
166 self.monitoring.validate()?;
167 self.raft.validate()?;
168 self.network.validate()?;
169 self.tls.validate()?;
170 self.retry.validate()?;
171 Ok(())
172 }
173}