Pulse/internal/api/reporting_runtime_snapshot.go
2026-03-18 16:06:30 +00:00

201 lines
6.5 KiB
Go

package api
import (
"context"
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
"github.com/rcourtman/pulse-go-rewrite/pkg/extensions"
)
func (h *ReportingHandlers) getRuntimeStateSnapshot(ctx context.Context, orgID string) (extensions.ReportingStateSnapshot, bool) {
sourceSnapshot, ok := h.getReportingEnrichmentSnapshot(ctx, orgID)
if !ok {
return extensions.EmptyReportingStateSnapshot(), false
}
runtimeSnapshot := extensions.EmptyReportingStateSnapshot()
runtimeSnapshot.Nodes = make([]extensions.ReportingNodeSnapshot, 0, len(sourceSnapshot.Nodes))
runtimeSnapshot.VMs = make([]extensions.ReportingVMSnapshot, 0, len(sourceSnapshot.VMs))
runtimeSnapshot.Containers = make([]extensions.ReportingContainerSnapshot, 0, len(sourceSnapshot.Containers))
runtimeSnapshot.ActiveAlerts = make([]extensions.ReportingAlertSnapshot, 0, len(sourceSnapshot.ActiveAlerts))
runtimeSnapshot.ResolvedAlerts = make([]extensions.ReportingAlertSnapshot, 0, len(sourceSnapshot.RecentlyResolved))
runtimeSnapshot.Storage = make([]extensions.ReportingStorageSnapshot, 0)
runtimeSnapshot.Disks = make([]extensions.ReportingDiskSnapshot, 0)
runtimeSnapshot.LegacyBackups = make([]extensions.ReportingLegacyBackupSnapshot, 0, len(sourceSnapshot.LegacyBackups.StorageBackups))
for _, node := range sourceSnapshot.Nodes {
var temperature *float64
if node.Temperature != nil && node.Temperature.CPUPackage > 0 {
value := node.Temperature.CPUPackage
temperature = &value
}
runtimeSnapshot.Nodes = append(runtimeSnapshot.Nodes, extensions.ReportingNodeSnapshot{
ID: node.ID,
Name: node.Name,
DisplayName: node.DisplayName,
Status: node.Status,
Host: node.Host,
Instance: node.Instance,
Uptime: node.Uptime,
KernelVersion: node.KernelVersion,
PVEVersion: node.PVEVersion,
CPUModel: node.CPUInfo.Model,
CPUCores: node.CPUInfo.Cores,
CPUSockets: node.CPUInfo.Sockets,
MemoryTotal: node.Memory.Total,
DiskTotal: node.Disk.Total,
LoadAverage: append([]float64(nil), node.LoadAverage...),
ClusterName: node.ClusterName,
IsCluster: node.IsClusterMember,
Temperature: temperature,
})
}
for _, vm := range sourceSnapshot.VMs {
runtimeSnapshot.VMs = append(runtimeSnapshot.VMs, extensions.ReportingVMSnapshot{
ID: vm.ID,
VMID: vm.VMID,
Name: vm.Name,
Status: vm.Status,
Node: vm.Node,
Instance: vm.Instance,
Uptime: vm.Uptime,
OSName: vm.OSName,
OSVersion: vm.OSVersion,
IPAddresses: append([]string(nil), vm.IPAddresses...),
CPUCores: vm.CPUs,
MemoryTotal: vm.Memory.Total,
DiskTotal: vm.Disk.Total,
Tags: append([]string(nil), vm.Tags...),
})
}
for _, ct := range sourceSnapshot.Containers {
runtimeSnapshot.Containers = append(runtimeSnapshot.Containers, extensions.ReportingContainerSnapshot{
ID: ct.ID,
VMID: ct.VMID,
Name: ct.Name,
Status: ct.Status,
Node: ct.Node,
Instance: ct.Instance,
Uptime: ct.Uptime,
OSName: ct.OSName,
IPAddresses: append([]string(nil), ct.IPAddresses...),
CPUCores: ct.CPUs,
MemoryTotal: ct.Memory.Total,
DiskTotal: ct.Disk.Total,
Tags: append([]string(nil), ct.Tags...),
})
}
for _, alert := range sourceSnapshot.ActiveAlerts {
runtimeSnapshot.ActiveAlerts = append(runtimeSnapshot.ActiveAlerts, extensions.ReportingAlertSnapshot{
ResourceID: alert.ResourceID,
Node: alert.Node,
Type: alert.Type,
Level: alert.Level,
Message: alert.Message,
Value: alert.Value,
Threshold: alert.Threshold,
StartTime: alert.StartTime,
})
}
for _, resolved := range sourceSnapshot.RecentlyResolved {
resolvedTime := resolved.ResolvedTime
runtimeSnapshot.ResolvedAlerts = append(runtimeSnapshot.ResolvedAlerts, extensions.ReportingAlertSnapshot{
ResourceID: resolved.ResourceID,
Node: resolved.Node,
Type: resolved.Type,
Level: resolved.Level,
Message: resolved.Message,
Value: resolved.Value,
Threshold: resolved.Threshold,
StartTime: resolved.StartTime,
ResolvedTime: &resolvedTime,
})
}
for _, backup := range sourceSnapshot.LegacyBackups.StorageBackups {
runtimeSnapshot.LegacyBackups = append(runtimeSnapshot.LegacyBackups, extensions.ReportingLegacyBackupSnapshot{
VMID: backup.VMID,
Node: backup.Node,
Storage: backup.Storage,
Timestamp: backup.Time,
Size: backup.Size,
Protected: backup.Protected,
VolID: backup.Volid,
})
}
for _, resource := range sourceSnapshot.Resources {
switch resource.Type {
case unifiedresources.ResourceTypeStorage:
storageNode := resource.ParentName
if storageNode == "" && len(resource.Identity.Hostnames) > 0 {
storageNode = resource.Identity.Hostnames[0]
}
var total, used, available int64
var usagePerc float64
if resource.Metrics != nil && resource.Metrics.Disk != nil {
if resource.Metrics.Disk.Total != nil {
total = *resource.Metrics.Disk.Total
}
if resource.Metrics.Disk.Used != nil {
used = *resource.Metrics.Disk.Used
}
if total > 0 {
available = total - used
}
usagePerc = resource.Metrics.Disk.Percent
if usagePerc == 0 && total > 0 {
usagePerc = (float64(used) / float64(total)) * 100
}
}
var storageType, content string
if resource.Storage != nil {
storageType = resource.Storage.Type
content = resource.Storage.Content
}
runtimeSnapshot.Storage = append(runtimeSnapshot.Storage, extensions.ReportingStorageSnapshot{
Name: resource.Name,
Node: storageNode,
Type: storageType,
Status: string(resource.Status),
Total: total,
Used: used,
Available: available,
UsagePerc: usagePerc,
Content: content,
})
case unifiedresources.ResourceTypePhysicalDisk:
if resource.PhysicalDisk == nil {
continue
}
diskNode := resource.ParentName
if diskNode == "" && len(resource.Identity.Hostnames) > 0 {
diskNode = resource.Identity.Hostnames[0]
}
disk := resource.PhysicalDisk
runtimeSnapshot.Disks = append(runtimeSnapshot.Disks, extensions.ReportingDiskSnapshot{
Node: diskNode,
Device: disk.DevPath,
Model: disk.Model,
Serial: disk.Serial,
Type: disk.DiskType,
Size: disk.SizeBytes,
Health: disk.Health,
Temperature: disk.Temperature,
WearLevel: disk.Wearout,
})
}
}
return runtimeSnapshot, true
}