Documentation
¶
Overview ¶
Package rollback plans and applies a return to an earlier control plane release. Applying is host-side only: the control plane process never replaces its own binary (see adr/028-release-rollback.md).
Index ¶
- Constants
- Variables
- func DBSchemaVersion(ctx context.Context, dbPath string) (int, error)
- func Dir(exe string) string
- func FileSHA256(path string) (string, int64, error)
- func Guard(plan Plan, opts Options) error
- func SwapInBackup(dbPath, backupPath string, now time.Time) (string, error)
- func UndoSwap(dbPath, aside string) error
- func ValidVersion(v string) bool
- func Verify(r Retained) error
- func WaitHealthy(ctx context.Context, base string, timeout time.Duration) error
- func WriteAudit(ctx context.Context, dbPath, actor, path string, now time.Time) error
- type BackupOption
- type Deps
- type Options
- type Plan
- type PlanInput
- type Result
- type Retained
- type Target
Constants ¶
const ( OutcomeApplied = "applied" OutcomeRecovered = "recovered" )
Outcomes of Apply.
const ( StepBackup = "backup" StepFetch = "fetch" StepVerify = "verify" StepStop = "stop" StepRestore = "restore_backup" StepSwap = "swap_binary" StepStart = "start" StepHealth = "verify_health" StepAutoRecover = "auto_recover" )
Step codes in a Plan. The dashboard and CLI translate them.
const ( SourceRetained = "retained" SourceManifest = "manifest" SourceUnknown = "unknown" )
Schema sources for a target.
const KeepCount = 3
KeepCount is how many release binaries stay on disk for instant, offline rollback.
Variables ¶
var ( ErrConfirmVersion = errors.New("typed confirmation does not match the target version") ErrNotRetained = errors.New("target release is not retained on this host") ErrSchemaNewer = errors.New("database schema is newer than the target release supports") ErrSchemaUnknown = errors.New("target release schema version is unknown") ErrRestoreNotNeeded = errors.New("a backup restore is not needed for this target") ErrBackupIncompatible = errors.New("backup is not compatible with the target release") ErrConfirmDataLoss = errors.New("data loss confirmation does not match the backup name") ErrRecovered = errors.New("target release failed to start, previous release restored") )
Refusals from Apply. Each is raised before anything is changed.
var ErrChecksum = errors.New("retained binary does not match its recorded checksum")
ErrChecksum means a retained binary no longer matches its recorded SHA-256.
var ErrInvalidVersion = errors.New("not a release version")
ErrInvalidVersion means a version string is not a release tag.
Functions ¶
func DBSchemaVersion ¶
DBSchemaVersion reads the schema version of the database file read-only. It never migrates, so it is safe against a database newer or older than the running binary.
func FileSHA256 ¶
FileSHA256 returns the hex SHA-256 and size of the file at path.
func SwapInBackup ¶
SwapInBackup moves the live database (and its WAL files) aside under a timestamped name and copies backupPath into place. It returns the aside path for UndoSwap.
func ValidVersion ¶
ValidVersion reports whether v looks like a release tag. It also keeps tags safe to use inside a file name.
func Verify ¶
Verify recomputes r's SHA-256 and compares it with the recorded one. A binary with no recorded checksum is refused: it was not retained by the verified install path.
func WaitHealthy ¶
WaitHealthy polls base+"/healthz" and base+"/readyz" until both return 2xx or timeout passes.
func WriteAudit ¶
WriteAudit inserts one audit_log row straight into the database file, without running migrations: the host process may be newer than the schema it just rolled back to, and opening the store would migrate it forward.
Types ¶
type BackupOption ¶
type BackupOption struct {
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
SchemaVersion int `json:"schema_version"`
Compatible bool `json:"compatible"`
}
BackupOption is a database backup a restore could use.
func ListBackups ¶
func ListBackups(ctx context.Context, dataDir string) ([]BackupOption, error)
ListBackups returns the newest local control plane backups with their schema versions (-1 when a file cannot be inspected).
type Deps ¶
type Deps struct {
BinaryPath string
ReleasesDir string
BinaryName string
// DBSchema reads the live database's schema version.
DBSchema func(ctx context.Context) (int, error)
// Backups lists restore points with their schema versions.
Backups func(ctx context.Context) ([]BackupOption, error)
// Backup takes a fresh backup of the live database and returns its name.
Backup func(ctx context.Context) (string, error)
Stop func(ctx context.Context) error
Start func(ctx context.Context) error
// WaitHealthy returns nil once the control plane answers its health and
// readiness probes, or an error when timeout passes first.
WaitHealthy func(ctx context.Context, timeout time.Duration) error
// RestoreDB swaps the named backup in and returns the path the previous
// database was kept at. UndoRestoreDB puts that path back.
RestoreDB func(ctx context.Context, backupName string) (string, error)
UndoRestoreDB func(ctx context.Context, keptPath string) error
// WriteMarker leaves the context the next boot records in upgrade history,
// and ClearMarker withdraws it when the target did not stay. Both optional.
WriteMarker func(ctx context.Context, backupName string) error
ClearMarker func()
// Audit records the outcome in the audit log. Best effort.
Audit func(ctx context.Context, detail string) error
Log *slog.Logger
Now func() time.Time
}
Deps are the host operations Apply drives. Tests fake them; the CLI wires real ones (systemd, sqlite, filesystem).
type Options ¶
type Options struct {
CurrentVersion string
ConfirmVersion string
RestoreBackup string
ConfirmDataLoss string
AcceptUnknown bool
HealthTimeout time.Duration
}
Options are the operator's choices for one rollback.
type Plan ¶
type Plan struct {
CurrentVersion string `json:"current_version"`
CurrentSchemaVersion int `json:"current_schema_version"`
Target Target `json:"target"`
Verdict upgrade.SchemaVerdict `json:"verdict"`
Steps []string `json:"steps"`
Warnings []string `json:"warnings"`
DowntimeSeconds int `json:"downtime_seconds"`
RestoreRequired bool `json:"restore_required"`
Backups []BackupOption `json:"backups"`
LossSince *time.Time `json:"data_loss_since,omitempty"`
Command string `json:"command"`
RestoreCommand string `json:"restore_command,omitempty"`
}
Plan is everything an operator needs to decide on a rollback.
type PlanInput ¶
type PlanInput struct {
CurrentVersion string
CurrentSchemaVersion int
DBSizeBytes int64
Target Target
Backups []BackupOption
ProgramName string
}
PlanInput is the facts BuildPlan needs, gathered by the caller.
type Result ¶
type Result struct {
Outcome string `json:"outcome"`
From string `json:"from"`
To string `json:"to"`
BackupName string `json:"backup_name,omitempty"`
Restored string `json:"restored_backup,omitempty"`
KeptDB string `json:"previous_database,omitempty"`
Plan Plan `json:"plan"`
HealthError string `json:"health_error,omitempty"`
}
Result reports what Apply did.
type Retained ¶
type Retained struct {
Version string `json:"version"`
Path string `json:"-"`
SHA256 string `json:"sha256"`
SizeBytes int64 `json:"size_bytes"`
SchemaVersion int `json:"schema_version"`
RetainedAt time.Time `json:"retained_at"`
}
Retained is one release binary kept on this host.
func List ¶
List returns retained binaries newest first, with the SHA-256 recorded when each was retained (not recomputed: Verify does that before use).