add: memory, storage, pcie collectors (1.4-1.6) — tested on real hardware
This commit is contained in:
98
audit/internal/collector/memory.go
Normal file
98
audit/internal/collector/memory.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"bee/audit/internal/schema"
|
||||
"log/slog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// collectMemory runs dmidecode -t 17 and returns all memory slots.
|
||||
func collectMemory() []schema.HardwareMemory {
|
||||
out, err := runDmidecode("17")
|
||||
if err != nil {
|
||||
slog.Warn("memory: dmidecode type 17 failed", "err", err)
|
||||
return nil
|
||||
}
|
||||
dimms := parseMemory(out)
|
||||
slog.Info("memory: collected", "count", len(dimms))
|
||||
return dimms
|
||||
}
|
||||
|
||||
func parseMemory(output string) []schema.HardwareMemory {
|
||||
sections := splitDMISections(output, "Memory Device")
|
||||
dimms := make([]schema.HardwareMemory, 0, len(sections))
|
||||
for _, fields := range sections {
|
||||
dimm := parseMemorySection(fields)
|
||||
dimms = append(dimms, dimm)
|
||||
}
|
||||
return dimms
|
||||
}
|
||||
|
||||
func parseMemorySection(fields map[string]string) schema.HardwareMemory {
|
||||
dimm := schema.HardwareMemory{}
|
||||
|
||||
if v := cleanDMIValue(fields["Locator"]); v != "" {
|
||||
dimm.Slot = &v
|
||||
}
|
||||
if v := cleanDMIValue(fields["Bank Locator"]); v != "" {
|
||||
dimm.Location = &v
|
||||
}
|
||||
|
||||
// presence: "No Module Installed" or size == 0
|
||||
present := true
|
||||
rawSize := fields["Size"]
|
||||
if strings.Contains(strings.ToLower(rawSize), "no module") || rawSize == "0" || rawSize == "" {
|
||||
present = false
|
||||
}
|
||||
dimm.Present = &present
|
||||
|
||||
if !present {
|
||||
status := "EMPTY"
|
||||
dimm.Status = &status
|
||||
return dimm
|
||||
}
|
||||
|
||||
status := "OK"
|
||||
dimm.Status = &status
|
||||
|
||||
if mb := parseMemorySizeMB(rawSize); mb > 0 {
|
||||
dimm.SizeMB = &mb
|
||||
}
|
||||
if v := cleanDMIValue(fields["Type"]); v != "" && v != "Unknown" {
|
||||
dimm.Type = &v
|
||||
}
|
||||
if mhz := parseInt(strings.TrimSuffix(fields["Speed"], " MT/s")); mhz > 0 {
|
||||
dimm.MaxSpeedMHz = &mhz
|
||||
}
|
||||
if mhz := parseInt(strings.TrimSuffix(fields["Configured Memory Speed"], " MT/s")); mhz > 0 {
|
||||
dimm.CurrentSpeedMHz = &mhz
|
||||
}
|
||||
if v := cleanDMIValue(fields["Manufacturer"]); v != "" {
|
||||
dimm.Manufacturer = &v
|
||||
}
|
||||
if v := cleanDMIValue(fields["Serial Number"]); v != "" {
|
||||
dimm.SerialNumber = &v
|
||||
}
|
||||
if v := cleanDMIValue(fields["Part Number"]); v != "" {
|
||||
p := strings.TrimSpace(v)
|
||||
dimm.PartNumber = &p
|
||||
}
|
||||
|
||||
return dimm
|
||||
}
|
||||
|
||||
// parseMemorySizeMB parses DMI size strings: "8 GB", "2048 MB", "No Module Installed".
|
||||
func parseMemorySizeMB(s string) int {
|
||||
s = strings.TrimSpace(s)
|
||||
if strings.Contains(strings.ToLower(s), "no module") {
|
||||
return 0
|
||||
}
|
||||
if strings.HasSuffix(s, " GB") {
|
||||
n := parseInt(strings.TrimSuffix(s, " GB"))
|
||||
return n * 1024
|
||||
}
|
||||
if strings.HasSuffix(s, " MB") {
|
||||
return parseInt(strings.TrimSuffix(s, " MB"))
|
||||
}
|
||||
return parseInt(s)
|
||||
}
|
||||
Reference in New Issue
Block a user