package orchestrator import ( "fmt" "time" "github.com/Fimeg/RedFlag/aggregator-agent/internal/client" "github.com/Fimeg/RedFlag/aggregator-agent/internal/system" ) // SystemScanner scans system metrics (CPU, memory, processes, uptime) type SystemScanner struct { agentVersion string } // NewSystemScanner creates a new system scanner func NewSystemScanner(agentVersion string) *SystemScanner { return &SystemScanner{ agentVersion: agentVersion, } } // IsAvailable always returns true since system scanning is always available func (s *SystemScanner) IsAvailable() bool { return true } // ScanSystem collects system information and returns proper system metrics func (s *SystemScanner) ScanSystem() ([]SystemMetric, error) { sysInfo, err := system.GetSystemInfo(s.agentVersion) if err != nil { return nil, fmt.Errorf("failed to get system info: %w", err) } // Convert system info to proper SystemMetric format var metrics []SystemMetric // CPU info metric cpuMetric := SystemMetric{ MetricName: "system-cpu", MetricType: "cpu", CurrentValue: fmt.Sprintf("%d cores, %d threads", sysInfo.CPUInfo.Cores, sysInfo.CPUInfo.Threads), AvailableValue: sysInfo.CPUInfo.ModelName, Severity: "low", Metadata: map[string]interface{}{ "cpu_model": sysInfo.CPUInfo.ModelName, "cpu_cores": sysInfo.CPUInfo.Cores, "cpu_threads": sysInfo.CPUInfo.Threads, }, } metrics = append(metrics, cpuMetric) // Memory info metric memMetric := SystemMetric{ MetricName: "system-memory", MetricType: "memory", CurrentValue: fmt.Sprintf("%.1f%% used", sysInfo.MemoryInfo.UsedPercent), AvailableValue: fmt.Sprintf("%d GB total", sysInfo.MemoryInfo.Total/(1024*1024*1024)), Severity: determineMemorySeverity(sysInfo.MemoryInfo.UsedPercent), Metadata: map[string]interface{}{ "memory_total": sysInfo.MemoryInfo.Total, "memory_used": sysInfo.MemoryInfo.Used, "memory_available": sysInfo.MemoryInfo.Available, "memory_used_percent": sysInfo.MemoryInfo.UsedPercent, }, } metrics = append(metrics, memMetric) // Process count metric processMetric := SystemMetric{ MetricName: "system-processes", MetricType: "processes", CurrentValue: fmt.Sprintf("%d processes", sysInfo.RunningProcesses), AvailableValue: "n/a", Severity: "low", Metadata: map[string]interface{}{ "process_count": sysInfo.RunningProcesses, }, } metrics = append(metrics, processMetric) // Uptime metric uptimeMetric := SystemMetric{ MetricName: "system-uptime", MetricType: "uptime", CurrentValue: sysInfo.Uptime, AvailableValue: "n/a", Severity: "low", Metadata: map[string]interface{}{ "uptime": sysInfo.Uptime, }, } metrics = append(metrics, uptimeMetric) // Reboot required metric (if applicable) if sysInfo.RebootRequired { rebootMetric := SystemMetric{ MetricName: "system-reboot", MetricType: "reboot", CurrentValue: "required", AvailableValue: "n/a", Severity: "important", Metadata: map[string]interface{}{ "reboot_required": true, "reboot_reason": sysInfo.RebootReason, }, } metrics = append(metrics, rebootMetric) } return metrics, nil } // Name returns the scanner name func (s *SystemScanner) Name() string { return "System Metrics Reporter" } // --- Legacy Compatibility Methods --- // Scan collects system information and returns it as "updates" for reporting (LEGACY) // This method is kept for backwards compatibility with the old Scanner interface func (s *SystemScanner) Scan() ([]client.UpdateReportItem, error) { metrics, err := s.ScanSystem() if err != nil { return nil, err } // Convert proper SystemMetric back to legacy UpdateReportItem format var items []client.UpdateReportItem for _, metric := range metrics { item := client.UpdateReportItem{ PackageName: metric.MetricName, CurrentVersion: metric.CurrentValue, AvailableVersion: metric.AvailableValue, PackageType: "system", Severity: metric.Severity, PackageDescription: fmt.Sprintf("System %s: %s", metric.MetricType, metric.MetricName), Metadata: metric.Metadata, } items = append(items, item) } return items, nil } // --- Typed Scanner Implementation --- // GetType returns the scanner type func (s *SystemScanner) GetType() ScannerType { return ScannerTypeSystem } // ScanTyped returns typed results (new implementation) func (s *SystemScanner) ScanTyped() (TypedScannerResult, error) { startTime := time.Now() metrics, err := s.ScanSystem() if err != nil { return TypedScannerResult{ ScannerName: s.Name(), ScannerType: ScannerTypeSystem, Error: err, Status: "failed", Duration: time.Since(startTime).Milliseconds(), }, err } return TypedScannerResult{ ScannerName: s.Name(), ScannerType: ScannerTypeSystem, SystemData: metrics, Status: "success", Duration: time.Since(startTime).Milliseconds(), }, nil } // determineMemorySeverity returns severity based on memory usage percentage func determineMemorySeverity(usedPercent float64) string { switch { case usedPercent >= 95: return "critical" case usedPercent >= 90: return "important" case usedPercent >= 80: return "moderate" default: return "low" } }