224 lines
4.4 KiB
Go
224 lines
4.4 KiB
Go
package exporter
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"encoding/json"
|
|
"io"
|
|
"strings"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
// Exporter handles data export in various formats
|
|
type Exporter struct {
|
|
result *models.AnalysisResult
|
|
}
|
|
|
|
// New creates a new exporter
|
|
func New(result *models.AnalysisResult) *Exporter {
|
|
return &Exporter{result: result}
|
|
}
|
|
|
|
// ExportCSV exports serial numbers to CSV format
|
|
func (e *Exporter) ExportCSV(w io.Writer) error {
|
|
writer := csv.NewWriter(w)
|
|
defer writer.Flush()
|
|
|
|
// Header
|
|
if err := writer.Write([]string{"Component", "Serial Number", "Manufacturer", "Location"}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if e.result == nil {
|
|
return nil
|
|
}
|
|
|
|
// FRU data
|
|
for _, fru := range e.result.FRU {
|
|
if !hasUsableSerial(fru.SerialNumber) {
|
|
continue
|
|
}
|
|
name := fru.ProductName
|
|
if name == "" {
|
|
name = fru.Description
|
|
}
|
|
if err := writer.Write([]string{
|
|
name,
|
|
fru.SerialNumber,
|
|
fru.Manufacturer,
|
|
fru.PartNumber,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Hardware data
|
|
if e.result.Hardware != nil {
|
|
// Board
|
|
if hasUsableSerial(e.result.Hardware.BoardInfo.SerialNumber) {
|
|
if err := writer.Write([]string{
|
|
e.result.Hardware.BoardInfo.ProductName,
|
|
strings.TrimSpace(e.result.Hardware.BoardInfo.SerialNumber),
|
|
e.result.Hardware.BoardInfo.Manufacturer,
|
|
"Board",
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// CPUs
|
|
for _, cpu := range e.result.Hardware.CPUs {
|
|
if !hasUsableSerial(cpu.SerialNumber) {
|
|
continue
|
|
}
|
|
if err := writer.Write([]string{
|
|
cpu.Model,
|
|
strings.TrimSpace(cpu.SerialNumber),
|
|
"",
|
|
"CPU",
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Memory
|
|
for _, mem := range e.result.Hardware.Memory {
|
|
if !hasUsableSerial(mem.SerialNumber) {
|
|
continue
|
|
}
|
|
location := mem.Location
|
|
if location == "" {
|
|
location = mem.Slot
|
|
}
|
|
if err := writer.Write([]string{
|
|
mem.PartNumber,
|
|
strings.TrimSpace(mem.SerialNumber),
|
|
mem.Manufacturer,
|
|
location,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Storage
|
|
for _, stor := range e.result.Hardware.Storage {
|
|
if !hasUsableSerial(stor.SerialNumber) {
|
|
continue
|
|
}
|
|
if err := writer.Write([]string{
|
|
stor.Model,
|
|
strings.TrimSpace(stor.SerialNumber),
|
|
stor.Manufacturer,
|
|
stor.Slot,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// GPUs
|
|
for _, gpu := range e.result.Hardware.GPUs {
|
|
if !hasUsableSerial(gpu.SerialNumber) {
|
|
continue
|
|
}
|
|
component := gpu.Model
|
|
if component == "" {
|
|
component = "GPU"
|
|
}
|
|
if err := writer.Write([]string{
|
|
component,
|
|
strings.TrimSpace(gpu.SerialNumber),
|
|
gpu.Manufacturer,
|
|
gpu.Slot,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// PCIe devices
|
|
for _, pcie := range e.result.Hardware.PCIeDevices {
|
|
if !hasUsableSerial(pcie.SerialNumber) {
|
|
continue
|
|
}
|
|
if err := writer.Write([]string{
|
|
pcie.DeviceClass,
|
|
strings.TrimSpace(pcie.SerialNumber),
|
|
pcie.Manufacturer,
|
|
pcie.Slot,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Network adapters
|
|
for _, nic := range e.result.Hardware.NetworkAdapters {
|
|
if !hasUsableSerial(nic.SerialNumber) {
|
|
continue
|
|
}
|
|
location := nic.Location
|
|
if location == "" {
|
|
location = nic.Slot
|
|
}
|
|
if err := writer.Write([]string{
|
|
nic.Model,
|
|
strings.TrimSpace(nic.SerialNumber),
|
|
nic.Vendor,
|
|
location,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Legacy network cards
|
|
for _, nic := range e.result.Hardware.NetworkCards {
|
|
if !hasUsableSerial(nic.SerialNumber) {
|
|
continue
|
|
}
|
|
if err := writer.Write([]string{
|
|
nic.Model,
|
|
strings.TrimSpace(nic.SerialNumber),
|
|
"",
|
|
"Network",
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Power supplies
|
|
for _, psu := range e.result.Hardware.PowerSupply {
|
|
if !hasUsableSerial(psu.SerialNumber) {
|
|
continue
|
|
}
|
|
if err := writer.Write([]string{
|
|
psu.Model,
|
|
strings.TrimSpace(psu.SerialNumber),
|
|
psu.Vendor,
|
|
psu.Slot,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExportJSON exports all data to JSON format
|
|
func (e *Exporter) ExportJSON(w io.Writer) error {
|
|
encoder := json.NewEncoder(w)
|
|
encoder.SetIndent("", " ")
|
|
return encoder.Encode(e.result)
|
|
}
|
|
|
|
func hasUsableSerial(serial string) bool {
|
|
s := strings.TrimSpace(serial)
|
|
if s == "" {
|
|
return false
|
|
}
|
|
switch strings.ToUpper(s) {
|
|
case "N/A", "NA", "NONE", "NULL", "UNKNOWN", "-":
|
|
return false
|
|
default:
|
|
return true
|
|
}
|
|
}
|