1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ProductionConfig {
37 pub security: SecurityConfig,
39 pub observability: ObservabilityConfig,
41 pub resilience: ResilienceConfig,
43 pub runtime: RuntimeConfig,
45 pub memory: MemoryConfig,
47 pub environment: String,
49 pub service_name: String,
51 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 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 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 pub fn high_performance() -> Self {
99 Self {
100 security: SecurityConfig::default(),
101 observability: ObservabilityConfig::default(),
102 resilience: ResilienceConfig::production(), runtime: RuntimeConfig::high_performance(),
104 memory: MemoryConfig::high_performance(),
105 environment: "high-performance".to_string(),
106 ..Default::default()
107 }
108 }
109
110 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 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 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 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 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 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 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 pub fn validate(&self) -> Result<()> {
182 self.runtime
183 .validate()
184 .map_err(|e| KernelError::ConfigError(e.to_string()))?;
185
186 if self.environment == "production" {
188 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 pub fn with_environment(mut self, env: impl Into<String>) -> Self {
199 self.environment = env.into();
200 self
201 }
202
203 pub fn with_service_name(mut self, name: impl Into<String>) -> Self {
205 self.service_name = name.into();
206 self
207 }
208
209 pub fn with_service_version(mut self, version: impl Into<String>) -> Self {
211 self.service_version = version.into();
212 self
213 }
214
215 pub fn with_security(mut self, config: SecurityConfig) -> Self {
217 self.security = config;
218 self
219 }
220
221 pub fn with_observability(mut self, config: ObservabilityConfig) -> Self {
223 self.observability = config;
224 self
225 }
226
227 pub fn with_resilience(mut self, config: ResilienceConfig) -> Self {
229 self.resilience = config;
230 self
231 }
232
233 pub fn with_runtime(mut self, config: RuntimeConfig) -> Self {
235 self.runtime = config;
236 self
237 }
238
239 pub fn with_memory(mut self, config: MemoryConfig) -> Self {
241 self.memory = config;
242 self
243 }
244}
245
246#[derive(Default)]
248pub struct ProductionConfigBuilder {
249 config: ProductionConfig,
250}
251
252impl ProductionConfigBuilder {
253 pub fn new() -> Self {
255 Self::default()
256 }
257
258 pub fn production() -> Self {
260 Self {
261 config: ProductionConfig::production(),
262 }
263 }
264
265 pub fn development() -> Self {
267 Self {
268 config: ProductionConfig::development(),
269 }
270 }
271
272 pub fn high_performance() -> Self {
274 Self {
275 config: ProductionConfig::high_performance(),
276 }
277 }
278
279 pub fn environment(mut self, env: impl Into<String>) -> Self {
281 self.config.environment = env.into();
282 self
283 }
284
285 pub fn service_name(mut self, name: impl Into<String>) -> Self {
287 self.config.service_name = name.into();
288 self
289 }
290
291 pub fn security(mut self, f: impl FnOnce(SecurityConfig) -> SecurityConfig) -> Self {
293 self.config.security = f(self.config.security);
294 self
295 }
296
297 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 pub fn resilience(mut self, f: impl FnOnce(ResilienceConfig) -> ResilienceConfig) -> Self {
308 self.config.resilience = f(self.config.resilience);
309 self
310 }
311
312 pub fn runtime(mut self, f: impl FnOnce(RuntimeConfig) -> RuntimeConfig) -> Self {
314 self.config.runtime = f(self.config.runtime);
315 self
316 }
317
318 pub fn memory(mut self, f: impl FnOnce(MemoryConfig) -> MemoryConfig) -> Self {
320 self.config.memory = f(self.config.memory);
321 self
322 }
323
324 pub fn build(self) -> Result<ProductionConfig> {
326 self.config.validate()?;
327 Ok(self.config)
328 }
329
330 pub fn build_unchecked(self) -> ProductionConfig {
332 self.config
333 }
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct HealthEndpointConfig {
339 pub enabled: bool,
341 pub liveness_path: String,
343 pub readiness_path: String,
345 pub startup_path: String,
347 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#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct MetricsEndpointConfig {
366 pub enabled: bool,
368 pub path: String,
370 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}