Related to #692: Skip unsupported guest OS info calls

This commit is contained in:
rcourtman 2025-11-12 19:17:09 +00:00
parent b829d86d2c
commit 923293fbf7
2 changed files with 119 additions and 48 deletions

View file

@ -1,6 +1,7 @@
package monitoring package monitoring
import ( import (
"errors"
"fmt" "fmt"
"math" "math"
"testing" "testing"
@ -278,3 +279,41 @@ func TestConvertPoolInfoToModelNil(t *testing.T) {
t.Fatalf("expected nil result for nil input") t.Fatalf("expected nil result for nil input")
} }
} }
func TestIsGuestAgentOSInfoUnsupportedError(t *testing.T) {
t.Parallel()
cases := []struct {
name string
err error
want bool
}{
{name: "nil error", err: nil, want: false},
{name: "unrelated error", err: errors.New("guest agent timeout"), want: false},
{
name: "missing os-release path",
err: errors.New(`API error 500: {"errors":{"message":"guest agent command failed: Failed to open file '/etc/os-release': No such file or directory"}}`),
want: true,
},
{
name: "missing usr lib os-release",
err: errors.New("API error 500: guest agent command failed: Failed to open file '/usr/lib/os-release': No such file or directory"),
want: true,
},
{
name: "unsupported command",
err: errors.New("API error 500: unsupported command: guest-get-osinfo"),
want: true,
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := isGuestAgentOSInfoUnsupportedError(tc.err); got != tc.want {
t.Fatalf("isGuestAgentOSInfoUnsupportedError(%v) = %v, want %v", tc.err, got, tc.want)
}
})
}
}

View file

@ -2485,6 +2485,16 @@ func (m *Monitor) fetchGuestAgentMetadata(ctx context.Context, client PVEClientI
return client.GetVMAgentInfo(ctx, nodeName, vmid) return client.GetVMAgentInfo(ctx, nodeName, vmid)
}) })
if err != nil { if err != nil {
if isGuestAgentOSInfoUnsupportedError(err) {
osInfoSkip = true
osInfoFailureCount = guestAgentOSInfoFailureThreshold
log.Warn().
Str("instance", instanceName).
Str("vm", vmName).
Int("vmid", vmid).
Err(err).
Msg("Guest agent OS info unsupported (missing os-release). Skipping future calls to avoid qemu-ga issues (refs #692)")
} else {
osInfoFailureCount++ osInfoFailureCount++
if osInfoFailureCount >= guestAgentOSInfoFailureThreshold { if osInfoFailureCount >= guestAgentOSInfoFailureThreshold {
osInfoSkip = true osInfoSkip = true
@ -2503,6 +2513,7 @@ func (m *Monitor) fetchGuestAgentMetadata(ctx context.Context, client PVEClientI
Err(err). Err(err).
Msg("Guest agent OS info unavailable") Msg("Guest agent OS info unavailable")
} }
}
} else if agentInfo, ok := agentInfoRaw.(map[string]interface{}); ok && len(agentInfo) > 0 { } else if agentInfo, ok := agentInfoRaw.(map[string]interface{}); ok && len(agentInfo) > 0 {
osName, osVersion = extractGuestOSInfo(agentInfo) osName, osVersion = extractGuestOSInfo(agentInfo)
osInfoFailureCount = 0 // Reset on success osInfoFailureCount = 0 // Reset on success
@ -2720,6 +2731,27 @@ func extractGuestOSInfo(data map[string]interface{}) (string, string) {
return osName, osVersion return osName, osVersion
} }
func isGuestAgentOSInfoUnsupportedError(err error) bool {
if err == nil {
return false
}
msg := strings.ToLower(err.Error())
// OpenBSD qemu-ga emits "Failed to open file '/etc/os-release'" (refs #692)
if strings.Contains(msg, "os-release") &&
(strings.Contains(msg, "failed to open file") || strings.Contains(msg, "no such file or directory")) {
return true
}
// Some Proxmox builds bubble up "unsupported command: guest-get-osinfo"
if strings.Contains(msg, "guest-get-osinfo") && strings.Contains(msg, "unsupported") {
return true
}
return false
}
func stringValue(val interface{}) string { func stringValue(val interface{}) string {
switch v := val.(type) { switch v := val.(type) {
case string: case string: