Fix backup status indicator not showing for guests

The backup status indicator feature was incomplete - it added the UI
component but never populated VM/Container LastBackup from actual
backup data. Now SyncGuestBackupTimes() is called after storage
backups and PBS backups are polled, matching each guest's VMID to
its most recent backup timestamp.

Fixes #786
This commit is contained in:
rcourtman 2025-11-30 22:13:46 +00:00
parent 6c1a0815ea
commit 54fab46bd6
2 changed files with 52 additions and 0 deletions

View file

@ -2,6 +2,7 @@ package models
import (
"sort"
"strconv"
"strings"
"sync"
"time"
@ -1118,6 +1119,51 @@ func (s *State) UpdateContainers(containers []Container) {
s.LastUpdate = time.Now()
}
// SyncGuestBackupTimes updates LastBackup on VMs and Containers from storage backups and PBS backups.
// Call this after updating storage backups or PBS backups to ensure guest backup indicators are accurate.
func (s *State) SyncGuestBackupTimes() {
s.mu.Lock()
defer s.mu.Unlock()
// Build a map of VMID -> latest backup time from all backup sources
latestBackup := make(map[int]time.Time)
// Process PVE storage backups
for _, backup := range s.PVEBackups.StorageBackups {
if backup.VMID <= 0 {
continue
}
if existing, ok := latestBackup[backup.VMID]; !ok || backup.Time.After(existing) {
latestBackup[backup.VMID] = backup.Time
}
}
// Process PBS backups (VMID is string, BackupTime is the timestamp)
for _, backup := range s.PBSBackups {
vmid, err := strconv.Atoi(backup.VMID)
if err != nil || vmid <= 0 {
continue
}
if existing, ok := latestBackup[vmid]; !ok || backup.BackupTime.After(existing) {
latestBackup[vmid] = backup.BackupTime
}
}
// Update VMs
for i := range s.VMs {
if backupTime, ok := latestBackup[s.VMs[i].VMID]; ok {
s.VMs[i].LastBackup = backupTime
}
}
// Update Containers
for i := range s.Containers {
if backupTime, ok := latestBackup[s.Containers[i].VMID]; ok {
s.Containers[i].LastBackup = backupTime
}
}
}
// UpdateContainersForInstance updates containers for a specific instance, merging with existing containers
func (s *State) UpdateContainersForInstance(instanceName string, containers []Container) {
s.mu.Lock()

View file

@ -8363,6 +8363,9 @@ func (m *Monitor) pollStorageBackupsWithNodes(ctx context.Context, instanceName
// Update state with storage backups for this instance
m.state.UpdateStorageBackupsForInstance(instanceName, allBackups)
// Sync backup times to VMs/Containers for backup status indicators
m.state.SyncGuestBackupTimes()
if m.alertManager != nil {
snapshot := m.state.GetSnapshot()
guestsByKey, guestsByVMID := buildGuestLookups(snapshot, m.guestMetadataStore)
@ -9289,6 +9292,9 @@ func (m *Monitor) pollPBSBackups(ctx context.Context, instanceName string, clien
// Update state
m.state.UpdatePBSBackups(instanceName, allBackups)
// Sync backup times to VMs/Containers for backup status indicators
m.state.SyncGuestBackupTimes()
if m.alertManager != nil {
snapshot := m.state.GetSnapshot()
guestsByKey, guestsByVMID := buildGuestLookups(snapshot, m.guestMetadataStore)