Pulse/internal/monitoring/vm_memory_carry_forward.go

116 lines
3.5 KiB
Go

package monitoring
import (
"math"
"strings"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/pkg/proxmox"
)
const (
vmMemoryCarryForwardMaxAge = 2 * time.Minute
vmMemoryHealthyGuestMaxAge = 10 * time.Minute
vmMemoryCarryForwardMinUsageDelta = 5.0
vmMemorySourceReliabilityLow = 0
vmMemorySourceReliabilityFallback = 1
vmMemorySourceReliabilityTrusted = 2
)
func vmMemorySourceReliability(source string) int {
switch strings.TrimSpace(source) {
case "meminfo-available", "meminfo-derived", "guest-agent-meminfo",
"rrd-memavailable", "rrd-memused", "host-agent":
return vmMemorySourceReliabilityTrusted
case "meminfo-total-minus-used", "previous-snapshot":
return vmMemorySourceReliabilityFallback
case "", "cluster-resources", "listing-mem", "status-mem", "status-freemem", "status-unavailable":
return vmMemorySourceReliabilityLow
default:
return vmMemorySourceReliabilityFallback
}
}
func shouldCarryForwardPreviousVMMemory(prev models.VM, currentStatus, currentSource string, currentTotal, currentUsed uint64, now time.Time) bool {
if currentStatus != "running" || prev.Type != "qemu" || prev.Status != "running" {
return false
}
if prev.Memory.Total <= 0 || prev.Memory.Used < 0 {
return false
}
if prev.LastSeen.IsZero() || now.Sub(prev.LastSeen) > vmMemoryCarryForwardMaxAge {
return false
}
prevReliability := vmMemorySourceReliability(prev.MemorySource)
currentReliability := vmMemorySourceReliability(currentSource)
if prevReliability < vmMemorySourceReliabilityTrusted || currentReliability > vmMemorySourceReliabilityFallback {
return false
}
if prevReliability <= currentReliability {
return false
}
if currentTotal > 0 && prev.Memory.Total > 0 && prev.Memory.Total != int64(currentTotal) {
return false
}
currentUsage := safePercentage(float64(currentUsed), float64(currentTotal))
if prev.Memory.Usage > 0 && math.Abs(prev.Memory.Usage-currentUsage) < vmMemoryCarryForwardMinUsageDelta {
return false
}
return true
}
func shouldCarryForwardHealthyGuestLowTrustVMMemory(prev models.VM, currentStatus, currentSource string, currentTotal, currentUsed uint64, now time.Time, guestAgentHealthy bool) bool {
if !guestAgentHealthy || currentStatus != "running" || prev.Type != "qemu" || prev.Status != "running" {
return false
}
if prev.Memory.Total <= 0 || prev.Memory.Used < 0 {
return false
}
if prev.LastSeen.IsZero() || now.Sub(prev.LastSeen) > vmMemoryHealthyGuestMaxAge {
return false
}
if currentTotal == 0 || prev.Memory.Total != int64(currentTotal) {
return false
}
if vmMemorySourceReliability(currentSource) != vmMemorySourceReliabilityLow {
return false
}
currentUsage := safePercentage(float64(currentUsed), float64(currentTotal))
if currentUsage < 99 {
return false
}
if prev.Memory.Usage >= 90 || math.Abs(prev.Memory.Usage-currentUsage) < vmMemoryCarryForwardMinUsageDelta {
return false
}
prevReliability := vmMemorySourceReliability(prev.MemorySource)
if prev.MemorySource != "previous-snapshot" && prevReliability < vmMemorySourceReliabilityTrusted {
return false
}
return true
}
func guestAgentSignalsHealthy(
detailedStatus *proxmox.VMStatus,
diskFromAgent bool,
ipAddresses []string,
networkInterfaces []models.GuestNetworkInterface,
osName, osVersion, agentVersion string,
) bool {
if detailedStatus != nil && detailedStatus.Agent.Value > 0 {
return true
}
return diskFromAgent ||
len(ipAddresses) > 0 ||
len(networkInterfaces) > 0 ||
osName != "" ||
osVersion != "" ||
agentVersion != ""
}