lib.rs
1 //! System requirements checking for AC/DC. 2 //! 3 //! This crate provides functionality to check if a system meets the requirements 4 //! for running various node roles in the ALPHA/DELTA network. 5 6 pub mod cpu; 7 pub mod environment; 8 pub mod gpu; 9 pub mod memory; 10 pub mod network; 11 pub mod ports; 12 pub mod storage; 13 14 use acdc_core::{NodeRole, Requirements, Result}; 15 use serde::{Deserialize, Serialize}; 16 17 /// Complete system information. 18 #[derive(Debug, Clone, Serialize, Deserialize)] 19 pub struct SystemInfo { 20 pub cpu: cpu::CpuInfo, 21 pub memory: memory::MemoryInfo, 22 pub storage: storage::StorageInfo, 23 pub gpu: Option<gpu::GpuInfo>, 24 pub network: network::NetworkInfo, 25 pub environment: environment::EnvironmentInfo, 26 } 27 28 impl SystemInfo { 29 /// Gather all system information. 30 pub fn gather() -> Result<Self> { 31 Ok(Self { 32 cpu: cpu::CpuInfo::detect()?, 33 memory: memory::MemoryInfo::detect()?, 34 storage: storage::StorageInfo::detect()?, 35 gpu: gpu::GpuInfo::detect().ok(), 36 network: network::NetworkInfo::detect()?, 37 environment: environment::EnvironmentInfo::detect()?, 38 }) 39 } 40 41 /// Check if the system meets requirements for a role. 42 pub fn check_role(&self, role: NodeRole) -> CheckResult { 43 let requirements = role.min_requirements(); 44 self.check_requirements(&requirements, role) 45 } 46 47 /// Check system against specific requirements. 48 pub fn check_requirements(&self, req: &Requirements, role: NodeRole) -> CheckResult { 49 let mut result = CheckResult { 50 role, 51 passed: true, 52 cpu: CheckStatus::pass("CPU cores sufficient"), 53 memory: CheckStatus::pass("Memory sufficient"), 54 storage: CheckStatus::pass("Storage sufficient"), 55 gpu: CheckStatus::pass("GPU not required"), 56 issues: Vec::new(), 57 }; 58 59 // CPU check 60 if self.cpu.physical_cores < req.cpu_cores { 61 result.passed = false; 62 result.cpu = CheckStatus::fail(format!( 63 "Need {} cores, have {}", 64 req.cpu_cores, self.cpu.physical_cores 65 )); 66 result.issues.push(format!( 67 "CPU: {} cores required, {} available", 68 req.cpu_cores, self.cpu.physical_cores 69 )); 70 } 71 72 // Memory check 73 let ram_gb = self.memory.total_bytes / (1024 * 1024 * 1024); 74 if ram_gb < req.ram_gb { 75 result.passed = false; 76 result.memory = 77 CheckStatus::fail(format!("Need {} GB RAM, have {} GB", req.ram_gb, ram_gb)); 78 result.issues.push(format!( 79 "Memory: {} GB required, {} GB available", 80 req.ram_gb, ram_gb 81 )); 82 } 83 84 // Storage check 85 let storage_gb = self.storage.available_bytes / (1024 * 1024 * 1024); 86 if storage_gb < req.storage_gb { 87 result.passed = false; 88 result.storage = CheckStatus::fail(format!( 89 "Need {} GB storage, have {} GB", 90 req.storage_gb, storage_gb 91 )); 92 result.issues.push(format!( 93 "Storage: {} GB required, {} GB available", 94 req.storage_gb, storage_gb 95 )); 96 } 97 98 // GPU check 99 if req.gpu_required { 100 match &self.gpu { 101 Some(gpu) if gpu.available => { 102 if let Some(required_vram) = req.gpu_vram_gb { 103 let vram_gb = gpu.vram_bytes / (1024 * 1024 * 1024); 104 if vram_gb < required_vram as u64 { 105 result.passed = false; 106 result.gpu = CheckStatus::fail(format!( 107 "Need {} GB VRAM, have {} GB", 108 required_vram, vram_gb 109 )); 110 result.issues.push(format!( 111 "GPU VRAM: {} GB required, {} GB available", 112 required_vram, vram_gb 113 )); 114 } else { 115 result.gpu = 116 CheckStatus::pass(format!("{} with {} GB VRAM", gpu.name, vram_gb)); 117 } 118 } 119 } 120 _ => { 121 result.passed = false; 122 result.gpu = CheckStatus::fail("GPU required but not detected"); 123 result 124 .issues 125 .push("GPU: Required but not detected".to_string()); 126 } 127 } 128 } 129 130 result 131 } 132 } 133 134 /// Result of a system requirements check. 135 #[derive(Debug, Clone, Serialize)] 136 pub struct CheckResult { 137 pub role: NodeRole, 138 pub passed: bool, 139 pub cpu: CheckStatus, 140 pub memory: CheckStatus, 141 pub storage: CheckStatus, 142 pub gpu: CheckStatus, 143 pub issues: Vec<String>, 144 } 145 146 /// Status of a single check. 147 #[derive(Debug, Clone, Serialize)] 148 pub struct CheckStatus { 149 pub passed: bool, 150 pub message: String, 151 } 152 153 impl CheckStatus { 154 pub fn pass(msg: impl Into<String>) -> Self { 155 Self { 156 passed: true, 157 message: msg.into(), 158 } 159 } 160 161 pub fn fail(msg: impl Into<String>) -> Self { 162 Self { 163 passed: false, 164 message: msg.into(), 165 } 166 } 167 } 168 169 /// Check if specific ports are available. 170 pub fn check_ports(ports: &[u16]) -> Vec<ports::PortStatus> { 171 ports.iter().map(|&p| ports::check_port(p)).collect() 172 }