rustkernel_core/config/
mod.rs

1//! Production Configuration Management
2//!
3//! Provides unified configuration for production deployments including:
4//! - Security settings
5//! - Observability configuration
6//! - Resilience patterns
7//! - Runtime parameters
8//! - Memory management
9//!
10//! # Example
11//!
12//! ```rust,ignore
13//! use rustkernel_core::config::ProductionConfig;
14//!
15//! // Load from environment
16//! let config = ProductionConfig::from_env()?;
17//!
18//! // Or load from file
19//! let config = ProductionConfig::from_file("config/production.toml")?;
20//!
21//! // Apply configuration
22//! config.apply().await?;
23//! ```
24
25use crate::error::{KernelError, Result};
26use crate::memory::MemoryConfig;
27use crate::observability::ObservabilityConfig;
28use crate::resilience::ResilienceConfig;
29use crate::runtime::RuntimeConfig;
30use crate::security::SecurityConfig;
31use serde::{Deserialize, Serialize};
32use std::path::Path;
33
34/// Unified production configuration
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ProductionConfig {
37    /// Security configuration
38    pub security: SecurityConfig,
39    /// Observability configuration
40    pub observability: ObservabilityConfig,
41    /// Resilience configuration
42    pub resilience: ResilienceConfig,
43    /// Runtime configuration
44    pub runtime: RuntimeConfig,
45    /// Memory configuration
46    pub memory: MemoryConfig,
47    /// Environment name
48    pub environment: String,
49    /// Service name
50    pub service_name: String,
51    /// Service version
52    pub service_version: String,
53}
54
55impl Default for ProductionConfig {
56    fn default() -> Self {
57        Self {
58            security: SecurityConfig::default(),
59            observability: ObservabilityConfig::default(),
60            resilience: ResilienceConfig::default(),
61            runtime: RuntimeConfig::default(),
62            memory: MemoryConfig::default(),
63            environment: "development".to_string(),
64            service_name: "rustkernels".to_string(),
65            service_version: env!("CARGO_PKG_VERSION").to_string(),
66        }
67    }
68}
69
70impl ProductionConfig {
71    /// Create development configuration
72    pub fn development() -> Self {
73        Self {
74            security: SecurityConfig::development(),
75            observability: ObservabilityConfig::development(),
76            resilience: ResilienceConfig::development(),
77            runtime: RuntimeConfig::development(),
78            memory: MemoryConfig::development(),
79            environment: "development".to_string(),
80            ..Default::default()
81        }
82    }
83
84    /// Create production configuration
85    pub fn production() -> Self {
86        Self {
87            security: SecurityConfig::production(),
88            observability: ObservabilityConfig::production(),
89            resilience: ResilienceConfig::production(),
90            runtime: RuntimeConfig::production(),
91            memory: MemoryConfig::production(),
92            environment: "production".to_string(),
93            ..Default::default()
94        }
95    }
96
97    /// Create high-performance configuration
98    pub fn high_performance() -> Self {
99        Self {
100            security: SecurityConfig::default(),
101            observability: ObservabilityConfig::default(),
102            resilience: ResilienceConfig::production(), // Use production resilience for high-perf
103            runtime: RuntimeConfig::high_performance(),
104            memory: MemoryConfig::high_performance(),
105            environment: "high-performance".to_string(),
106            ..Default::default()
107        }
108    }
109
110    /// Load configuration from environment variables
111    pub fn from_env() -> Result<Self> {
112        let mut config = match std::env::var("RUSTKERNEL_ENV")
113            .as_deref()
114            .unwrap_or("development")
115        {
116            "production" | "prod" => Self::production(),
117            "high-performance" | "hp" => Self::high_performance(),
118            _ => Self::development(),
119        };
120
121        // Override with specific environment variables
122        if let Ok(name) = std::env::var("RUSTKERNEL_SERVICE_NAME") {
123            config.service_name = name;
124        }
125
126        if let Ok(version) = std::env::var("RUSTKERNEL_SERVICE_VERSION") {
127            config.service_version = version;
128        }
129
130        // Security overrides
131        if std::env::var("RUSTKERNEL_AUTH_ENABLED").is_ok() {
132            config.security.rbac_enabled = true;
133        }
134
135        if std::env::var("RUSTKERNEL_MULTI_TENANT").is_ok() {
136            config.security.multi_tenancy_enabled = true;
137        }
138
139        // Runtime overrides
140        if let Ok(val) = std::env::var("RUSTKERNEL_GPU_ENABLED") {
141            config.runtime.gpu_enabled = val.parse().unwrap_or(true);
142        }
143
144        if let Ok(val) = std::env::var("RUSTKERNEL_MAX_INSTANCES") {
145            if let Ok(n) = val.parse() {
146                config.runtime.max_kernel_instances = n;
147            }
148        }
149
150        // Memory overrides
151        if let Ok(val) = std::env::var("RUSTKERNEL_MAX_GPU_MEMORY_GB") {
152            if let Ok(gb) = val.parse::<u64>() {
153                config.memory.max_gpu_memory = gb * 1024 * 1024 * 1024;
154            }
155        }
156
157        Ok(config)
158    }
159
160    /// Load configuration from a TOML file
161    pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
162        let content = std::fs::read_to_string(path.as_ref())
163            .map_err(|e| KernelError::ConfigError(format!("Failed to read config: {}", e)))?;
164
165        toml::from_str(&content)
166            .map_err(|e| KernelError::ConfigError(format!("Failed to parse config: {}", e)))
167    }
168
169    /// Save configuration to a TOML file
170    pub fn to_file(&self, path: impl AsRef<Path>) -> Result<()> {
171        let content = toml::to_string_pretty(self)
172            .map_err(|e| KernelError::ConfigError(format!("Failed to serialize config: {}", e)))?;
173
174        std::fs::write(path.as_ref(), content)
175            .map_err(|e| KernelError::ConfigError(format!("Failed to write config: {}", e)))?;
176
177        Ok(())
178    }
179
180    /// Validate the configuration
181    pub fn validate(&self) -> Result<()> {
182        self.runtime
183            .validate()
184            .map_err(|e| KernelError::ConfigError(e.to_string()))?;
185
186        // Additional validation
187        if self.environment == "production" {
188            // Production should have security enabled
189            if !self.security.rbac_enabled && self.security.auth.is_none() {
190                tracing::warn!("Production environment without authentication or RBAC enabled");
191            }
192        }
193
194        Ok(())
195    }
196
197    /// Set environment
198    pub fn with_environment(mut self, env: impl Into<String>) -> Self {
199        self.environment = env.into();
200        self
201    }
202
203    /// Set service name
204    pub fn with_service_name(mut self, name: impl Into<String>) -> Self {
205        self.service_name = name.into();
206        self
207    }
208
209    /// Set service version
210    pub fn with_service_version(mut self, version: impl Into<String>) -> Self {
211        self.service_version = version.into();
212        self
213    }
214
215    /// Set security configuration
216    pub fn with_security(mut self, config: SecurityConfig) -> Self {
217        self.security = config;
218        self
219    }
220
221    /// Set observability configuration
222    pub fn with_observability(mut self, config: ObservabilityConfig) -> Self {
223        self.observability = config;
224        self
225    }
226
227    /// Set resilience configuration
228    pub fn with_resilience(mut self, config: ResilienceConfig) -> Self {
229        self.resilience = config;
230        self
231    }
232
233    /// Set runtime configuration
234    pub fn with_runtime(mut self, config: RuntimeConfig) -> Self {
235        self.runtime = config;
236        self
237    }
238
239    /// Set memory configuration
240    pub fn with_memory(mut self, config: MemoryConfig) -> Self {
241        self.memory = config;
242        self
243    }
244}
245
246/// Configuration builder
247#[derive(Default)]
248pub struct ProductionConfigBuilder {
249    config: ProductionConfig,
250}
251
252impl ProductionConfigBuilder {
253    /// Create new builder
254    pub fn new() -> Self {
255        Self::default()
256    }
257
258    /// Start from production preset
259    pub fn production() -> Self {
260        Self {
261            config: ProductionConfig::production(),
262        }
263    }
264
265    /// Start from development preset
266    pub fn development() -> Self {
267        Self {
268            config: ProductionConfig::development(),
269        }
270    }
271
272    /// Start from high-performance preset
273    pub fn high_performance() -> Self {
274        Self {
275            config: ProductionConfig::high_performance(),
276        }
277    }
278
279    /// Set environment
280    pub fn environment(mut self, env: impl Into<String>) -> Self {
281        self.config.environment = env.into();
282        self
283    }
284
285    /// Set service name
286    pub fn service_name(mut self, name: impl Into<String>) -> Self {
287        self.config.service_name = name.into();
288        self
289    }
290
291    /// Configure security
292    pub fn security(mut self, f: impl FnOnce(SecurityConfig) -> SecurityConfig) -> Self {
293        self.config.security = f(self.config.security);
294        self
295    }
296
297    /// Configure observability
298    pub fn observability(
299        mut self,
300        f: impl FnOnce(ObservabilityConfig) -> ObservabilityConfig,
301    ) -> Self {
302        self.config.observability = f(self.config.observability);
303        self
304    }
305
306    /// Configure resilience
307    pub fn resilience(mut self, f: impl FnOnce(ResilienceConfig) -> ResilienceConfig) -> Self {
308        self.config.resilience = f(self.config.resilience);
309        self
310    }
311
312    /// Configure runtime
313    pub fn runtime(mut self, f: impl FnOnce(RuntimeConfig) -> RuntimeConfig) -> Self {
314        self.config.runtime = f(self.config.runtime);
315        self
316    }
317
318    /// Configure memory
319    pub fn memory(mut self, f: impl FnOnce(MemoryConfig) -> MemoryConfig) -> Self {
320        self.config.memory = f(self.config.memory);
321        self
322    }
323
324    /// Build and validate the configuration
325    pub fn build(self) -> Result<ProductionConfig> {
326        self.config.validate()?;
327        Ok(self.config)
328    }
329
330    /// Build without validation
331    pub fn build_unchecked(self) -> ProductionConfig {
332        self.config
333    }
334}
335
336/// Health endpoint configuration
337#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct HealthEndpointConfig {
339    /// Enable health endpoints
340    pub enabled: bool,
341    /// Liveness endpoint path
342    pub liveness_path: String,
343    /// Readiness endpoint path
344    pub readiness_path: String,
345    /// Startup endpoint path
346    pub startup_path: String,
347    /// Include detailed health info
348    pub detailed: bool,
349}
350
351impl Default for HealthEndpointConfig {
352    fn default() -> Self {
353        Self {
354            enabled: true,
355            liveness_path: "/health/live".to_string(),
356            readiness_path: "/health/ready".to_string(),
357            startup_path: "/health/startup".to_string(),
358            detailed: false,
359        }
360    }
361}
362
363/// Metrics endpoint configuration
364#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct MetricsEndpointConfig {
366    /// Enable metrics endpoint
367    pub enabled: bool,
368    /// Metrics endpoint path
369    pub path: String,
370    /// Include detailed histogram buckets
371    pub detailed_histograms: bool,
372}
373
374impl Default for MetricsEndpointConfig {
375    fn default() -> Self {
376        Self {
377            enabled: true,
378            path: "/metrics".to_string(),
379            detailed_histograms: false,
380        }
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use super::*;
387
388    #[test]
389    fn test_default_config() {
390        let config = ProductionConfig::default();
391        assert_eq!(config.environment, "development");
392        assert_eq!(config.service_name, "rustkernels");
393    }
394
395    #[test]
396    fn test_production_config() {
397        let config = ProductionConfig::production();
398        assert_eq!(config.environment, "production");
399        assert!(config.security.rbac_enabled);
400        assert!(config.security.audit_logging);
401    }
402
403    #[test]
404    fn test_development_config() {
405        let config = ProductionConfig::development();
406        assert_eq!(config.environment, "development");
407    }
408
409    #[test]
410    fn test_builder() {
411        let config = ProductionConfigBuilder::production()
412            .service_name("test-service")
413            .environment("staging")
414            .build_unchecked();
415
416        assert_eq!(config.service_name, "test-service");
417        assert_eq!(config.environment, "staging");
418    }
419
420    #[test]
421    fn test_config_validation() {
422        let config = ProductionConfig::development();
423        assert!(config.validate().is_ok());
424    }
425
426    #[test]
427    fn test_with_methods() {
428        let config = ProductionConfig::default()
429            .with_environment("staging")
430            .with_service_name("my-service");
431
432        assert_eq!(config.environment, "staging");
433        assert_eq!(config.service_name, "my-service");
434    }
435}