mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 03:20:11 +00:00
Preserve fresh guest metadata across transient agent misses (#1319)
This commit is contained in:
parent
608f184666
commit
d91f21b961
2 changed files with 94 additions and 12 deletions
|
|
@ -326,16 +326,6 @@ func (m *Monitor) retryGuestAgentCall(ctx context.Context, timeout time.Duration
|
|||
}
|
||||
|
||||
func (m *Monitor) fetchGuestAgentMetadata(ctx context.Context, client PVEClientInterface, instanceName, nodeName, vmName string, vmid int, vmStatus *proxmox.VMStatus) ([]string, []models.GuestNetworkInterface, string, string, string) {
|
||||
if vmStatus == nil || client == nil {
|
||||
m.clearGuestMetadataCache(instanceName, nodeName, vmid)
|
||||
return nil, nil, "", "", ""
|
||||
}
|
||||
|
||||
if vmStatus.Agent.Value <= 0 {
|
||||
m.clearGuestMetadataCache(instanceName, nodeName, vmid)
|
||||
return nil, nil, "", "", ""
|
||||
}
|
||||
|
||||
key := guestMetadataCacheKey(instanceName, nodeName, vmid)
|
||||
now := time.Now()
|
||||
|
||||
|
|
@ -343,6 +333,14 @@ func (m *Monitor) fetchGuestAgentMetadata(ctx context.Context, client PVEClientI
|
|||
cached, ok := m.guestMetadataCache[key]
|
||||
m.guestMetadataMu.RUnlock()
|
||||
|
||||
if vmStatus == nil || client == nil || vmStatus.Agent.Value <= 0 {
|
||||
if ok && now.Sub(cached.fetchedAt) < guestMetadataCacheEntryTTL(cached) {
|
||||
return cloneStringSlice(cached.ipAddresses), cloneGuestNetworkInterfaces(cached.networkInterfaces), cached.osName, cached.osVersion, cached.agentVersion
|
||||
}
|
||||
m.clearGuestMetadataCache(instanceName, nodeName, vmid)
|
||||
return nil, nil, "", "", ""
|
||||
}
|
||||
|
||||
if ok && now.Sub(cached.fetchedAt) < guestMetadataCacheEntryTTL(cached) {
|
||||
return cloneStringSlice(cached.ipAddresses), cloneGuestNetworkInterfaces(cached.networkInterfaces), cached.osName, cached.osVersion, cached.agentVersion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -819,6 +819,90 @@ func TestFetchGuestAgentMetadataPreservesCachedValuesOnEmptyResponses(t *testing
|
|||
}
|
||||
}
|
||||
|
||||
func TestFetchGuestAgentMetadataPreservesFreshCacheWhenAgentTemporarilyUnavailable(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
key := guestMetadataCacheKey("pve", "node1", 100)
|
||||
cachedFetchedAt := time.Now().Add(-time.Minute)
|
||||
|
||||
newMonitor := func() *Monitor {
|
||||
return &Monitor{
|
||||
guestMetadataCache: map[string]guestMetadataCacheEntry{
|
||||
key: {
|
||||
ipAddresses: []string{"192.168.1.10"},
|
||||
networkInterfaces: []models.GuestNetworkInterface{
|
||||
{Name: "eth0", MAC: "00:11:22:33:44:55", Addresses: []string{"192.168.1.10"}},
|
||||
},
|
||||
osName: "Ubuntu",
|
||||
osVersion: "24.04",
|
||||
agentVersion: "8.2.0",
|
||||
fetchedAt: cachedFetchedAt,
|
||||
},
|
||||
},
|
||||
guestMetadataLimiter: make(map[string]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
assertCachePreserved := func(t *testing.T, monitor *Monitor, gotIPs []string, gotIfaces []models.GuestNetworkInterface, gotOSName, gotOSVersion, gotAgentVersion string) {
|
||||
t.Helper()
|
||||
|
||||
if len(gotIPs) != 1 || gotIPs[0] != "192.168.1.10" {
|
||||
t.Fatalf("expected cached IPs to be preserved, got %#v", gotIPs)
|
||||
}
|
||||
if len(gotIfaces) != 1 || gotIfaces[0].Name != "eth0" {
|
||||
t.Fatalf("expected cached interfaces to be preserved, got %#v", gotIfaces)
|
||||
}
|
||||
if gotOSName != "Ubuntu" || gotOSVersion != "24.04" {
|
||||
t.Fatalf("expected cached OS info to be preserved, got %q %q", gotOSName, gotOSVersion)
|
||||
}
|
||||
if gotAgentVersion != "8.2.0" {
|
||||
t.Fatalf("expected cached agent version to be preserved, got %q", gotAgentVersion)
|
||||
}
|
||||
|
||||
entry, ok := monitor.guestMetadataCache[key]
|
||||
if !ok {
|
||||
t.Fatal("expected guest metadata cache entry to remain populated")
|
||||
}
|
||||
if len(entry.networkInterfaces) != 1 || entry.networkInterfaces[0].Name != "eth0" {
|
||||
t.Fatalf("expected cached interfaces to remain populated, got %#v", entry.networkInterfaces)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("nil vm status keeps fresh cache", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
monitor := newMonitor()
|
||||
gotIPs, gotIfaces, gotOSName, gotOSVersion, gotAgentVersion := monitor.fetchGuestAgentMetadata(
|
||||
context.Background(),
|
||||
&emptyGuestMetadataClient{},
|
||||
"pve",
|
||||
"node1",
|
||||
"vm100",
|
||||
100,
|
||||
nil,
|
||||
)
|
||||
|
||||
assertCachePreserved(t, monitor, gotIPs, gotIfaces, gotOSName, gotOSVersion, gotAgentVersion)
|
||||
})
|
||||
|
||||
t.Run("agent temporarily unavailable keeps fresh cache", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
monitor := newMonitor()
|
||||
gotIPs, gotIfaces, gotOSName, gotOSVersion, gotAgentVersion := monitor.fetchGuestAgentMetadata(
|
||||
context.Background(),
|
||||
&emptyGuestMetadataClient{},
|
||||
"pve",
|
||||
"node1",
|
||||
"vm100",
|
||||
100,
|
||||
&proxmox.VMStatus{Agent: proxmox.VMAgentField{Value: 0}},
|
||||
)
|
||||
|
||||
assertCachePreserved(t, monitor, gotIPs, gotIfaces, gotOSName, gotOSVersion, gotAgentVersion)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGuestMetadataCacheEntryTTL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -828,9 +912,9 @@ func TestGuestMetadataCacheEntryTTL(t *testing.T) {
|
|||
want time.Duration
|
||||
}{
|
||||
{
|
||||
name: "empty entry retries quickly",
|
||||
name: "empty entry retries quickly",
|
||||
entry: guestMetadataCacheEntry{},
|
||||
want: guestMetadataEmptyTTL,
|
||||
want: guestMetadataEmptyTTL,
|
||||
},
|
||||
{
|
||||
name: "network metadata uses full ttl",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue