package stacks import "log" // carryLifeRecords copies, from the app.yaml a restore is about to replace (prior, as on disk), the records // that describe the app's LIFE on this box rather than its definition (R-697, v0.276.0). The restore's // write is a fresh AppConfig by design — the env, the locked fields and the pin come from the unit — and it // used to drop these with it: // // - conversion_copy + earlier_conversion_copies: a kept pre-conversion datadir copy whose record is dropped // is never released (R-697, measured on 9202). A restore does not remove the volume, so it must not // forget it either. // - desired_state: the household's intent. Dropped, a dead app after a restore was read as "unknown // intent" and never alarmed (R-166's absent case). // - failed_update_step, last_update_undone, last_auto_update: the ladder's history on THIS box; the // automatic leg must not re-press a step that already failed here because a restore happened. // // NOT carried: pinned_images (the restore pins to the unit's definition right after — carrying the old pin // would freeze a failed SetPin onto the wrong version), installed_images (an observation of what ran // before the restore, possibly another version), restored_logins (computed per restore). // Pinned by TestR697_ARestoreKeepsTheConversionCopyRecordSoTheCopyIsReleased. func carryLifeRecords(logger *log.Logger, name string, prior, cfg *AppConfig) { if prior == nil { return } cfg.ConversionCopy = prior.ConversionCopy cfg.EarlierConversionCopies = prior.EarlierConversionCopies if cfg.DesiredState == "" { cfg.DesiredState = prior.DesiredState } cfg.FailedStep = prior.FailedStep cfg.LastUpdateUndone = prior.LastUpdateUndone cfg.LastAutoUpdate = prior.LastAutoUpdate cfg.AfterInstall = prior.AfterInstall // v0.279.0: what the install's one-time command did stays true after a restore // v0.280.0 (decision 46): the setup gate is the app's life here too. A restore never re-gates an app whose gate // opened; a gate that was still closed stays closed (its probe opens it if the restored data is set up). // No prior record (a removed app, kept data, a rebuilt guest) = no gate: the data comes back with its admin. cfg.SetupGate = prior.SetupGate cfg.InstallHold = prior.InstallHold // R-741: the loop opens it when the restored record says the login was replaced cfg.DefaultLogin = prior.DefaultLogin cfg.AfterSetup = prior.AfterSetup if n := len(prior.EarlierConversionCopies); prior.ConversionCopy != nil || n > 0 { cur := "" if prior.ConversionCopy != nil { cur = prior.ConversionCopy.Copy } logger.Printf("[INFO] [stacks] %s: the restore keeps the record of the kept pre-conversion copy %q (+%d earlier) — it is released when a backup written by the converted engine is proven", name, cur, n) } }