Files
Redflag/aggregator-agent/internal/orchestrator/storage_scanner.go
Fimeg 38894f64d3 feat: add config sync endpoint and security UI updates
- Add GET /api/v1/agents/:id/config endpoint for server configuration
- Agent fetches config during check-in and applies updates
- Add version tracking to prevent unnecessary config applications
- Clean separation: config sync independent of commands
- Fix agent UI subsystem settings to actually control agent behavior
- Update Security Health UI with frosted glass styling and tooltips
2025-11-03 22:36:26 -05:00

147 lines
3.9 KiB
Go

package orchestrator
import (
"fmt"
"time"
"github.com/Fimeg/RedFlag/aggregator-agent/internal/client"
"github.com/Fimeg/RedFlag/aggregator-agent/internal/system"
)
// StorageScanner scans disk usage metrics
type StorageScanner struct {
agentVersion string
}
// NewStorageScanner creates a new storage scanner
func NewStorageScanner(agentVersion string) *StorageScanner {
return &StorageScanner{
agentVersion: agentVersion,
}
}
// IsAvailable always returns true since storage scanning is always available
func (s *StorageScanner) IsAvailable() bool {
return true
}
// ScanStorage collects disk usage information and returns proper storage metrics
func (s *StorageScanner) ScanStorage() ([]StorageMetric, error) {
sysInfo, err := system.GetSystemInfo(s.agentVersion)
if err != nil {
return nil, fmt.Errorf("failed to get system info: %w", err)
}
if len(sysInfo.DiskInfo) == 0 {
return nil, fmt.Errorf("no disk information available")
}
// Convert disk info to proper StorageMetric format
var metrics []StorageMetric
for _, disk := range sysInfo.DiskInfo {
metric := StorageMetric{
Mountpoint: disk.Mountpoint,
Filesystem: disk.Filesystem,
Device: disk.Device,
DiskType: disk.DiskType,
TotalBytes: int64(disk.Total),
UsedBytes: int64(disk.Used),
AvailableBytes: int64(disk.Available),
UsedPercent: disk.UsedPercent,
IsRoot: disk.IsRoot,
IsLargest: disk.IsLargest,
Severity: determineDiskSeverity(disk.UsedPercent),
Metadata: map[string]interface{}{
"agent_version": s.agentVersion,
"collected_at": time.Now().Format(time.RFC3339),
},
}
metrics = append(metrics, metric)
}
return metrics, nil
}
// Name returns the scanner name
func (s *StorageScanner) Name() string {
return "Disk Usage Reporter"
}
// --- Legacy Compatibility Methods ---
// Scan collects disk usage information and returns it as "updates" for reporting (LEGACY)
// This method is kept for backwards compatibility with the old Scanner interface
func (s *StorageScanner) Scan() ([]client.UpdateReportItem, error) {
metrics, err := s.ScanStorage()
if err != nil {
return nil, err
}
// Convert proper StorageMetric back to legacy UpdateReportItem format
var items []client.UpdateReportItem
for _, metric := range metrics {
item := client.UpdateReportItem{
PackageName: fmt.Sprintf("disk-%s", metric.Mountpoint),
CurrentVersion: fmt.Sprintf("%.1f%% used", metric.UsedPercent),
AvailableVersion: fmt.Sprintf("%d GB available", metric.AvailableBytes/(1024*1024*1024)),
PackageType: "storage",
Severity: metric.Severity,
PackageDescription: fmt.Sprintf("Disk: %s (%s) - %s", metric.Mountpoint, metric.Filesystem, metric.Device),
Metadata: metric.Metadata,
}
items = append(items, item)
}
return items, nil
}
// --- Typed Scanner Implementation ---
// GetType returns the scanner type
func (s *StorageScanner) GetType() ScannerType {
return ScannerTypeStorage
}
// ScanTyped returns typed results (new implementation)
func (s *StorageScanner) ScanTyped() (TypedScannerResult, error) {
startTime := time.Now()
defer func() {
// Duration will be set at the end
}()
metrics, err := s.ScanStorage()
if err != nil {
return TypedScannerResult{
ScannerName: s.Name(),
ScannerType: ScannerTypeStorage,
Error: err,
Status: "failed",
Duration: time.Since(startTime).Milliseconds(),
}, err
}
return TypedScannerResult{
ScannerName: s.Name(),
ScannerType: ScannerTypeStorage,
StorageData: metrics,
Status: "success",
Duration: time.Since(startTime).Milliseconds(),
}, nil
}
// determineDiskSeverity returns severity based on disk usage percentage
func determineDiskSeverity(usedPercent float64) string {
switch {
case usedPercent >= 95:
return "critical"
case usedPercent >= 90:
return "important"
case usedPercent >= 80:
return "moderate"
default:
return "low"
}
}