R-1288: a restore of a set-aside unit sets the replaced install's unit aside at once, with no alarm. R-1282: the later media restart time is stored and resumed at start, once. Red-proved. Commit only.
gates / gates (push) Successful in 1m26s

This commit is contained in:
2026-10-25 21:37:55 +01:00
parent a79a292d72
commit b5863a96eb
8 changed files with 274 additions and 13 deletions
+34
View File
@@ -323,5 +323,39 @@ func (m *Manager) RestoreSetAsideUnit(id string) (string, UnitRestoreResult, err
}
m.logger.Printf("[INFO] [backup] restore %s from the set-aside unit %s (an earlier install, D47)", k.Source, k.Path)
res, err := m.RestoreFromRecoveryUnitAt(k.Source, k.Path)
if err == nil || errors.Is(err, ErrRestoreNotStarted) {
// The restored data stays in both cases (D49 = A), so the app is now the set-aside unit's install.
m.retireReplacedUnit(k.Source)
}
return k.Source, res, err
}
// retireReplacedUnit (R-1288): after the household restored an earlier install's set-aside unit, the app's primary
// unit belongs to the install the restore REPLACED. It is set aside here, at the restore — moved whole, never deleted
// (D47), one log line and NO operator alarm: the household chose this restore, so nothing unexpected happened. Before,
// the next backup's writer found it and set it aside with a second alarm and a second kept copy that looked like a
// reinstall. A unit that is already this install's (or none) is left alone; a move that fails leaves it for the next
// writer, whose guard sets it aside as before.
func (m *Manager) retireReplacedUnit(stack string) {
nsRoot := m.namespaceRoot(m.GetAppDrivePath(stack))
unitDir := RecoveryUnitPath(nsRoot, stack)
exists, unitID, unitSecrets := unitOwnerOf(unitDir)
if !exists {
return
}
liveID, liveSecrets, err := m.liveInstall(stack)
if err != nil {
m.logger.Printf("[WARN] [backup] %s: after the restore of an earlier install, this install's identity cannot be read (%v) — the replaced unit is left for the next backup's check (D47)", stack, err)
return
}
if v, _ := unitOwnerVerdict(unitID, liveID, unitSecrets, liveSecrets); v != ownerOther {
return
}
dest, err := m.setAsideUnit(stack, unitDir, nsRoot)
if err != nil {
m.logger.Printf("[WARN] [backup] %s: the unit of the install the restore replaced (%s) could not be set aside: %v — the next backup's check sets it aside (D47)", stack, orUnknown(unitID), err)
return
}
m.logger.Printf("[INFO] [backup] %s: the unit of the install the restore replaced (%s) is set aside whole → %s — replaced by the restored install %s; no alarm (R-1288, D47)",
stack, orUnknown(unitID), dest, orUnknown(liveID))
}