Documentation
¶
Overview ¶
Package rehydrate plans and runs the data half of a whole-server recovery: after the control plane itself is restored, it pulls each database and app volume back from its latest usable backup and reports what happened.
Index ¶
Constants ¶
const ( EnvMaxBackupAge = "APP_REHYDRATE_MAX_BACKUP_AGE" EnvConcurrency = "APP_REHYDRATE_CONCURRENCY" )
Environment variables that tune a rehydrate pass.
const ( KindDatabase = "database" KindVolume = "volume" )
Item kinds.
const ( StatusPlanned = "planned" StatusRunning = "running" StatusSucceeded = "succeeded" StatusFailed = "failed" StatusSkipped = "skipped" StatusBlocked = "blocked" )
Item statuses. Planned is the dry-run state of an item a run would restore.
const ( ReasonNoBackup = "no_backup" ReasonBackupTooOld = "backup_too_old" ReasonNoBackupsEngine = "engine_keeps_no_data" )
Reasons an item is skipped or blocked.
const ( StateRunning = "running" StatePlanned = "planned" StateSucceeded = "succeeded" StatePartial = "partial" StateFailed = "failed" )
Report states.
const ( ModePlan = "plan" ModeRun = "run" )
Modes of a report.
Variables ¶
var ErrBusy = errors.New("rehydrate: a run is already in progress")
ErrBusy is returned when a run is already in progress.
var ErrNotConfigured = errors.New("rehydrate: restores are not configured")
ErrNotConfigured is returned when restores cannot run on this control plane.
Functions ¶
This section is empty.
Types ¶
type Backup ¶
type Backup struct {
ID string
Kind string
Database string
App string
Volume string
Succeeded bool
FinishedAt time.Time
SizeBytes int64
}
Backup is one backup attempt, reduced to what planning needs.
type BackupRef ¶
type BackupRef struct {
ID string `json:"id"`
FinishedAt time.Time `json:"finished_at"`
SizeBytes int64 `json:"size_bytes"`
AgeSeconds int64 `json:"age_seconds"`
}
BackupRef is the backup an item restores from.
type Config ¶
type Config struct {
// MaxBackupAge is the oldest backup a run will restore from; 0 disables the check.
MaxBackupAge time.Duration
Concurrency int
}
Config holds the env-driven limits.
type Database ¶
type Database struct {
Name string
Engine string
// Stateless engines keep nothing on disk and have nothing to restore.
Stateless bool
}
Database is one desired database.
type Inventory ¶
type Inventory interface {
Databases(ctx context.Context) ([]Database, error)
Volumes(ctx context.Context) ([]Volume, error)
Backups(ctx context.Context) ([]Backup, error)
}
Inventory reads what the restored control plane believes should exist.
type Item ¶
type Item struct {
ID string `json:"id"`
Kind string `json:"kind"`
App string `json:"app,omitempty"`
Volume string `json:"volume,omitempty"`
Database string `json:"database,omitempty"`
Engine string `json:"engine,omitempty"`
Status string `json:"status"`
Reason string `json:"reason,omitempty"`
Backup *BackupRef `json:"backup,omitempty"`
RestoreID string `json:"restore_id,omitempty"`
Error string `json:"error,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
}
Item is one resource in the plan and, after a run, its outcome.
type PlanOptions ¶
type PlanOptions struct {
// AllowStale restores from backups older than MaxBackupAge instead of blocking them.
AllowStale bool
}
PlanOptions tunes planning.
type Report ¶
type Report struct {
ID string `json:"id"`
Mode string `json:"mode"`
State string `json:"state"`
GeneratedAt time.Time `json:"generated_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
MaxBackupAgeSeconds int64 `json:"max_backup_age_seconds"`
Concurrency int `json:"concurrency"`
AllowStale bool `json:"allow_stale"`
Items []Item `json:"items"`
Summary Summary `json:"summary"`
}
Report is the plan and the DR report of a run; the same shape serves both.
type Restorer ¶
type Restorer interface {
RestoreDatabase(ctx context.Context, d Database, backupID string) (string, error)
RestoreVolume(ctx context.Context, v Volume, backupID string) (string, error)
}
Restorer applies one backup through the existing restore runners and blocks until it finishes. It returns the restore history ID.
type RunStore ¶
type RunStore interface {
SaveRehydrateRun(ctx context.Context, r store.RehydrateRun) error
LatestRehydrateRun(ctx context.Context) (store.RehydrateRun, error)
}
RunStore persists the latest report so it survives a restart mid-recovery.
type Service ¶
type Service struct {
Inventory Inventory
Restorer Restorer // nil means restores are not configured
Store RunStore // nil keeps the report in memory only
Config Config
Logger *slog.Logger
Now func() time.Time
// contains filtered or unexported fields
}
Service plans, runs and remembers rehydrate passes. One run at a time.
type Summary ¶
type Summary struct {
Total int `json:"total"`
Restorable int `json:"restorable"`
Succeeded int `json:"succeeded"`
Failed int `json:"failed"`
Skipped int `json:"skipped"`
Blocked int `json:"blocked"`
// WorstBackupAgeSeconds is the data-loss window: the oldest backup used or planned.
WorstBackupAgeSeconds int64 `json:"worst_backup_age_seconds"`
}
Summary counts items by outcome.