controllerswap: F1 verify hardening — reject crash-looping no-healthcheck image v0.47.0
controllerHealthy reads RestartCount (running&&rc>0 -> not ok) + signals needsDwell for no-healthcheck; verify requires verifyDwell(=3) consecutive ok polls for a no-healthcheck image (real healthcheck trusted immediately). Closes the F1 hole (alpine crash-loop passed the point-in-time check). Red-proof + dwell + real-image tests. No sudoers/orchestration change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
This commit is contained in:
@@ -89,7 +89,11 @@ func (f *fakeBackups) BackupWithSnapshotHook(_ context.Context, vmid int, onSnap
|
||||
}
|
||||
return hub.Backup{VMID: vmid, Success: true, Archive: "local:backup/vzdump-x", StartedAt: "2026-06-10T00:00:00Z"}, nil
|
||||
}
|
||||
func (f *fakeBackups) called() []int { f.mu.Lock(); defer f.mu.Unlock(); return append([]int(nil), f.vmids...) }
|
||||
func (f *fakeBackups) called() []int {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return append([]int(nil), f.vmids...)
|
||||
}
|
||||
|
||||
type fakeStore struct {
|
||||
mu sync.Mutex
|
||||
@@ -97,7 +101,11 @@ type fakeStore struct {
|
||||
tests []hub.RestoreTest
|
||||
}
|
||||
|
||||
func (s *fakeStore) RecordBackup(b hub.Backup) { s.mu.Lock(); s.backups = append(s.backups, b); s.mu.Unlock() }
|
||||
func (s *fakeStore) RecordBackup(b hub.Backup) {
|
||||
s.mu.Lock()
|
||||
s.backups = append(s.backups, b)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
func (s *fakeStore) Backups(context.Context) []hub.Backup {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user