use crate::error::{KernelError, Result};
use crate::memory::MemoryConfig;
use crate::observability::ObservabilityConfig;
use crate::resilience::ResilienceConfig;
use crate::runtime::RuntimeConfig;
use crate::security::SecurityConfig;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProductionConfig {
pub security: SecurityConfig,
pub observability: ObservabilityConfig,
pub resilience: ResilienceConfig,
pub runtime: RuntimeConfig,
pub memory: MemoryConfig,
pub environment: String,
pub service_name: String,
pub service_version: String,
}
impl Default for ProductionConfig {
fn default() -> Self {
Self {
security: SecurityConfig::default(),
observability: ObservabilityConfig::default(),
resilience: ResilienceConfig::default(),
runtime: RuntimeConfig::default(),
memory: MemoryConfig::default(),
environment: "development".to_string(),
service_name: "rustkernels".to_string(),
service_version: env!("CARGO_PKG_VERSION").to_string(),
}
}
}
impl ProductionConfig {
pub fn development() -> Self {
Self {
security: SecurityConfig::development(),
observability: ObservabilityConfig::development(),
resilience: ResilienceConfig::development(),
runtime: RuntimeConfig::development(),
memory: MemoryConfig::development(),
environment: "development".to_string(),
..Default::default()
}
}
pub fn production() -> Self {
Self {
security: SecurityConfig::production(),
observability: ObservabilityConfig::production(),
resilience: ResilienceConfig::production(),
runtime: RuntimeConfig::production(),
memory: MemoryConfig::production(),
environment: "production".to_string(),
..Default::default()
}
}
pub fn high_performance() -> Self {
Self {
security: SecurityConfig::default(),
observability: ObservabilityConfig::default(),
resilience: ResilienceConfig::production(), runtime: RuntimeConfig::high_performance(),
memory: MemoryConfig::high_performance(),
environment: "high-performance".to_string(),
..Default::default()
}
}
pub fn from_env() -> Result<Self> {
let mut config = match std::env::var("RUSTKERNEL_ENV")
.as_deref()
.unwrap_or("development")
{
"production" | "prod" => Self::production(),
"high-performance" | "hp" => Self::high_performance(),
_ => Self::development(),
};
if let Ok(name) = std::env::var("RUSTKERNEL_SERVICE_NAME") {
config.service_name = name;
}
if let Ok(version) = std::env::var("RUSTKERNEL_SERVICE_VERSION") {
config.service_version = version;
}
if std::env::var("RUSTKERNEL_AUTH_ENABLED").is_ok() {
config.security.rbac_enabled = true;
}
if std::env::var("RUSTKERNEL_MULTI_TENANT").is_ok() {
config.security.multi_tenancy_enabled = true;
}
if let Ok(val) = std::env::var("RUSTKERNEL_GPU_ENABLED") {
config.runtime.gpu_enabled = val.parse().unwrap_or(true);
}
if let Ok(val) = std::env::var("RUSTKERNEL_MAX_INSTANCES") {
if let Ok(n) = val.parse() {
config.runtime.max_kernel_instances = n;
}
}
if let Ok(val) = std::env::var("RUSTKERNEL_MAX_GPU_MEMORY_GB") {
if let Ok(gb) = val.parse::<u64>() {
config.memory.max_gpu_memory = gb * 1024 * 1024 * 1024;
}
}
Ok(config)
}
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
let content = std::fs::read_to_string(path.as_ref())
.map_err(|e| KernelError::ConfigError(format!("Failed to read config: {}", e)))?;
toml::from_str(&content)
.map_err(|e| KernelError::ConfigError(format!("Failed to parse config: {}", e)))
}
pub fn to_file(&self, path: impl AsRef<Path>) -> Result<()> {
let content = toml::to_string_pretty(self)
.map_err(|e| KernelError::ConfigError(format!("Failed to serialize config: {}", e)))?;
std::fs::write(path.as_ref(), content)
.map_err(|e| KernelError::ConfigError(format!("Failed to write config: {}", e)))?;
Ok(())
}
pub fn validate(&self) -> Result<()> {
self.runtime
.validate()
.map_err(|e| KernelError::ConfigError(e.to_string()))?;
if self.environment == "production" {
if !self.security.rbac_enabled && self.security.auth.is_none() {
tracing::warn!("Production environment without authentication or RBAC enabled");
}
}
Ok(())
}
pub fn with_environment(mut self, env: impl Into<String>) -> Self {
self.environment = env.into();
self
}
pub fn with_service_name(mut self, name: impl Into<String>) -> Self {
self.service_name = name.into();
self
}
pub fn with_service_version(mut self, version: impl Into<String>) -> Self {
self.service_version = version.into();
self
}
pub fn with_security(mut self, config: SecurityConfig) -> Self {
self.security = config;
self
}
pub fn with_observability(mut self, config: ObservabilityConfig) -> Self {
self.observability = config;
self
}
pub fn with_resilience(mut self, config: ResilienceConfig) -> Self {
self.resilience = config;
self
}
pub fn with_runtime(mut self, config: RuntimeConfig) -> Self {
self.runtime = config;
self
}
pub fn with_memory(mut self, config: MemoryConfig) -> Self {
self.memory = config;
self
}
}
#[derive(Default)]
pub struct ProductionConfigBuilder {
config: ProductionConfig,
}
impl ProductionConfigBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn production() -> Self {
Self {
config: ProductionConfig::production(),
}
}
pub fn development() -> Self {
Self {
config: ProductionConfig::development(),
}
}
pub fn high_performance() -> Self {
Self {
config: ProductionConfig::high_performance(),
}
}
pub fn environment(mut self, env: impl Into<String>) -> Self {
self.config.environment = env.into();
self
}
pub fn service_name(mut self, name: impl Into<String>) -> Self {
self.config.service_name = name.into();
self
}
pub fn security(mut self, f: impl FnOnce(SecurityConfig) -> SecurityConfig) -> Self {
self.config.security = f(self.config.security);
self
}
pub fn observability(
mut self,
f: impl FnOnce(ObservabilityConfig) -> ObservabilityConfig,
) -> Self {
self.config.observability = f(self.config.observability);
self
}
pub fn resilience(mut self, f: impl FnOnce(ResilienceConfig) -> ResilienceConfig) -> Self {
self.config.resilience = f(self.config.resilience);
self
}
pub fn runtime(mut self, f: impl FnOnce(RuntimeConfig) -> RuntimeConfig) -> Self {
self.config.runtime = f(self.config.runtime);
self
}
pub fn memory(mut self, f: impl FnOnce(MemoryConfig) -> MemoryConfig) -> Self {
self.config.memory = f(self.config.memory);
self
}
pub fn build(self) -> Result<ProductionConfig> {
self.config.validate()?;
Ok(self.config)
}
pub fn build_unchecked(self) -> ProductionConfig {
self.config
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthEndpointConfig {
pub enabled: bool,
pub liveness_path: String,
pub readiness_path: String,
pub startup_path: String,
pub detailed: bool,
}
impl Default for HealthEndpointConfig {
fn default() -> Self {
Self {
enabled: true,
liveness_path: "/health/live".to_string(),
readiness_path: "/health/ready".to_string(),
startup_path: "/health/startup".to_string(),
detailed: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricsEndpointConfig {
pub enabled: bool,
pub path: String,
pub detailed_histograms: bool,
}
impl Default for MetricsEndpointConfig {
fn default() -> Self {
Self {
enabled: true,
path: "/metrics".to_string(),
detailed_histograms: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = ProductionConfig::default();
assert_eq!(config.environment, "development");
assert_eq!(config.service_name, "rustkernels");
}
#[test]
fn test_production_config() {
let config = ProductionConfig::production();
assert_eq!(config.environment, "production");
assert!(config.security.rbac_enabled);
assert!(config.security.audit_logging);
}
#[test]
fn test_development_config() {
let config = ProductionConfig::development();
assert_eq!(config.environment, "development");
}
#[test]
fn test_builder() {
let config = ProductionConfigBuilder::production()
.service_name("test-service")
.environment("staging")
.build_unchecked();
assert_eq!(config.service_name, "test-service");
assert_eq!(config.environment, "staging");
}
#[test]
fn test_config_validation() {
let config = ProductionConfig::development();
assert!(config.validate().is_ok());
}
#[test]
fn test_with_methods() {
let config = ProductionConfig::default()
.with_environment("staging")
.with_service_name("my-service");
assert_eq!(config.environment, "staging");
assert_eq!(config.service_name, "my-service");
}
}