Documentation
¶
Overview ¶
Package dbupgrade advises on and automates minor and patch upgrades of managed databases: a curated version catalog, per database policies with a maintenance window, and a resumable runner that backs up, upgrades, verifies and reverts.
Index ¶
- Constants
- Variables
- func DurationFromEnv(key string, def time.Duration, logger *slog.Logger) time.Duration
- func HealthCommand(engine string) ([]string, error)
- func RefreshIntervalFromEnv(logger *slog.Logger) time.Duration
- func RevertPlan(imageRevert bool, snapshot, backupID string) []string
- type Advice
- type Advisor
- type Advisory
- type BackupRunner
- type Catalog
- type ChannelNotifier
- type ChannelStore
- type DockerHubLister
- type DockerRuntime
- func (d *DockerRuntime) BackupStatus(ctx context.Context, backupID string) (string, error)
- func (d *DockerRuntime) Busy(ctx context.Context, name string) (string, error)
- func (d *DockerRuntime) CheckImage(ctx context.Context, engine, version string) error
- func (d *DockerRuntime) Health(ctx context.Context, db store.DesiredDatabase, version string, deep bool) (bool, string, error)
- func (d *DockerRuntime) ImageDigest(ctx context.Context, name string) (string, error)
- func (d *DockerRuntime) RemoveVolume(ctx context.Context, volume string) error
- func (d *DockerRuntime) ResetData(ctx context.Context, name, version string) error
- func (d *DockerRuntime) RestoreBackup(ctx context.Context, restoreID, backupID string, db store.DesiredDatabase) error
- func (d *DockerRuntime) RestoreSnapshot(ctx context.Context, name, volume, version string) error
- func (d *DockerRuntime) Resume(ctx context.Context, name string) error
- func (d *DockerRuntime) RunBackup(ctx context.Context, backupID string, db store.DesiredDatabase) error
- func (d *DockerRuntime) RunVerify(ctx context.Context, verificationID, backupID, engine string) error
- func (d *DockerRuntime) SetVersion(ctx context.Context, name, version string) error
- func (d *DockerRuntime) SnapshotData(ctx context.Context, name, volume string) error
- func (d *DockerRuntime) VerifyStatus(ctx context.Context, backupID, verificationID string) (string, error)
- type DockerStore
- type EngineCatalog
- type Manager
- func (m *Manager) EffectivePolicy(ctx context.Context, name string) (Policy, bool, error)
- func (m *Manager) Overview(ctx context.Context, name string) (Overview, error)
- func (m *Manager) Run(ctx context.Context, interval time.Duration)
- func (m *Manager) SetPolicy(ctx context.Context, name string, p Policy, inherit bool, by string) error
- func (m *Manager) Summary(ctx context.Context, visible func(string) bool) ([]SummaryItem, error)
- func (m *Manager) Tick(ctx context.Context) error
- func (m *Manager) UpgradeNow(ctx context.Context, name, version, by string) (store.DBUpgradeRun, error)
- type NoticeSender
- type Notifier
- type Overview
- type Policy
- type Refresher
- type RestoreRunner
- type Runner
- type Runtime
- type Store
- type SummaryItem
- type SupportLine
- type TagLister
- type Target
- type VerifyRunner
- type VolumeRuntime
Constants ¶
const ( SupportSupported = "supported" SupportEOLSoon = "eol_soon" SupportEOL = "eol" SupportUnknown = "unknown" )
Support statuses of a database's current release line.
const ( EnvInterval = "APP_DB_UPGRADE_INTERVAL" EnvHealthTimeout = "APP_DB_UPGRADE_HEALTH_TIMEOUT" EnvMinWindowRemaining = "APP_DB_UPGRADE_MIN_WINDOW_REMAINING" EnvEOLWarn = "APP_DB_EOL_WARN" )
Environment knobs. Every threshold is configurable, none is hardcoded.
const ( DefaultInterval = time.Minute DefaultMinWindowRemaining = 30 * time.Minute DefaultEOLWarn = 180 * 24 * time.Hour )
Defaults for the knobs above.
const ( PhaseBackup = "backup" PhaseVerifyBackup = "verify_backup" PhasePreflight = "preflight" PhaseSnapshot = "snapshot" PhaseBump = "bump" PhaseHealth = "health" PhaseRevertImage = "revert_image" PhaseRevertSnapshot = "revert_snapshot" PhaseRevertBackup = "revert_backup" )
Phases inside a state. Persisted, so a restarted control plane resumes at the step it was on.
const ( RevertPathImage = "image" RevertPathSnapshot = "volume_snapshot" RevertPathBackup = "backup_restore" )
Revert paths recorded on a run so the history says how it was undone.
const ( KindPatch = "patch" KindMinor = "minor" KindMajor = "major" )
Upgrade kinds, ordered by risk.
const DefaultHealthTimeout = 5 * time.Minute
DefaultHealthTimeout bounds each wait for a healthy database; override with APP_DB_UPGRADE_HEALTH_TIMEOUT.
const DefaultRefreshInterval = 24 * time.Hour
DefaultRefreshInterval is daily: database releases ship monthly at most.
const EnvRefreshInterval = "APP_DB_VERSION_REFRESH_INTERVAL"
EnvRefreshInterval sets how often registry tags are refreshed; "0" disables it.
Variables ¶
var ( ErrNotFound = errors.New("database not found") ErrInvalid = errors.New("invalid upgrade request") ErrConflict = errors.New("upgrade conflict") )
Errors the API maps to status codes.
Functions ¶
func DurationFromEnv ¶
DurationFromEnv parses key as a Go duration, falling back to def.
func HealthCommand ¶
HealthCommand returns the in-container check for engine. It connects, runs a trivial query, checks the server is not a read-only replica where that applies, and prints the server version on its first line. Each check exits non-zero on failure.
func RefreshIntervalFromEnv ¶
RefreshIntervalFromEnv returns the configured interval, 0 when disabled.
func RevertPlan ¶
RevertPlan lists the revert phases a run will try, cheapest first: the old image on the same data, then the volume snapshot, then the logical backup. The image step is skipped for engines whose upgrade rewrites data files.
Types ¶
type Advice ¶
type Advice struct {
Engine string `json:"engine"`
Current string `json:"current"`
Comparable bool `json:"comparable"`
Floating bool `json:"floating"`
Line string `json:"line,omitempty"`
EOL string `json:"eol,omitempty"`
Support string `json:"support"`
Advisories []string `json:"advisories,omitempty"`
Targets []Target `json:"targets"`
AutoMax string `json:"auto_max"`
ImageRevert bool `json:"image_revert"`
ManualReason string `json:"manual_reason,omitempty"`
Notes string `json:"notes,omitempty"`
Note string `json:"note,omitempty"`
CatalogUpdated string `json:"catalog_updated"`
}
Advice is the advisor's view of one database.
func (Advice) BestAutomatic ¶
BestAutomatic picks the newest target the policy level and the engine both allow.
func (Advice) FindTarget ¶
FindTarget returns the advised target with that exact version.
func (Advice) HasSecurityUpdate ¶
HasSecurityUpdate reports whether any target fixes an advisory.
type Advisor ¶
type Advisor struct {
Catalog *Catalog
// EOLWarn is how long before end of life a line counts as eol_soon.
EOLWarn time.Duration
}
Advisor computes upgrade targets from a Catalog.
type Advisory ¶
Advisory lists the CVE ids fixed by each version in Fixed; a version is affected when it is older than the fixed version of its own line.
type BackupRunner ¶
type BackupRunner interface {
RunBackup(ctx context.Context, historyID, databaseName, engine, containerName, targetID string) error
}
BackupRunner takes a logical backup; *backup.Runner satisfies it.
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog is the embedded curated catalog plus any versions a background registry refresh discovered since start. Safe for concurrent use.
func (*Catalog) Engine ¶
func (c *Catalog) Engine(id string) (EngineCatalog, bool)
Engine returns an engine's catalog with discovered versions merged in.
func (*Catalog) SetDiscovered ¶
SetDiscovered replaces the refreshed versions for one engine.
type ChannelNotifier ¶
type ChannelNotifier struct {
Channels ChannelStore
Sender NoticeSender
}
ChannelNotifier sends upgrade notices through the alert channels an operator already connected (Slack, Discord, email, webhooks and so on).
type ChannelStore ¶
type ChannelStore interface {
GetNotificationChannel(ctx context.Context, id string) (*alerting.NotificationChannel, error)
}
ChannelStore loads alerting notification channels.
type DockerHubLister ¶
DockerHubLister reads tags from Docker Hub's public tag API.
type DockerRuntime ¶
type DockerRuntime struct {
Store DockerStore
Docker VolumeRuntime
Backups BackupRunner
Verifier VerifyRunner
Restorer RestoreRunner
// CopyVolume and WipeVolume are internal/backup's volume helpers.
CopyVolume func(ctx context.Context, rt docker.Runtime, src, dst string) error
WipeVolume func(ctx context.Context, rt docker.Runtime, name string) error
Nudge func()
// StopWait bounds the wait for the reconciler to stop a database.
StopWait time.Duration
}
DockerRuntime implements Runtime against the local Docker daemon and the existing backup, verification and restore runners.
func (*DockerRuntime) BackupStatus ¶
BackupStatus returns "" when the backup row does not exist.
func (*DockerRuntime) CheckImage ¶
func (d *DockerRuntime) CheckImage(ctx context.Context, engine, version string) error
CheckImage pulls the target image by creating and removing a throwaway container, so a missing tag fails before the database stops.
func (*DockerRuntime) Health ¶
func (d *DockerRuntime) Health(ctx context.Context, db store.DesiredDatabase, version string, deep bool) (bool, string, error)
Health checks the container runs version's image, then the engine check.
func (*DockerRuntime) ImageDigest ¶
ImageDigest returns the image ID the database container runs now.
func (*DockerRuntime) RemoveVolume ¶
func (d *DockerRuntime) RemoveVolume(ctx context.Context, volume string) error
RemoveVolume deletes a snapshot volume.
func (*DockerRuntime) ResetData ¶
func (d *DockerRuntime) ResetData(ctx context.Context, name, version string) error
ResetData empties the data volume and starts version on it fresh.
func (*DockerRuntime) RestoreBackup ¶
func (d *DockerRuntime) RestoreBackup(ctx context.Context, restoreID, backupID string, db store.DesiredDatabase) error
RestoreBackup restores the verified pre-upgrade backup.
func (*DockerRuntime) RestoreSnapshot ¶
func (d *DockerRuntime) RestoreSnapshot(ctx context.Context, name, volume, version string) error
RestoreSnapshot puts the snapshot back as the data volume on version.
func (*DockerRuntime) Resume ¶
func (d *DockerRuntime) Resume(ctx context.Context, name string) error
Resume clears the suspended flag so the reconciler starts the database.
func (*DockerRuntime) RunBackup ¶
func (d *DockerRuntime) RunBackup(ctx context.Context, backupID string, db store.DesiredDatabase) error
RunBackup takes a logical backup to the database's own backup target.
func (*DockerRuntime) RunVerify ¶
func (d *DockerRuntime) RunVerify(ctx context.Context, verificationID, backupID, engine string) error
RunVerify re-downloads the backup and checks its checksum and format.
func (*DockerRuntime) SetVersion ¶
func (d *DockerRuntime) SetVersion(ctx context.Context, name, version string) error
SetVersion is the set-version path: save the version, then let the reconciler recreate the container on the same data volume.
func (*DockerRuntime) SnapshotData ¶
func (d *DockerRuntime) SnapshotData(ctx context.Context, name, volume string) error
SnapshotData stops the database and copies its data volume into volume.
func (*DockerRuntime) VerifyStatus ¶
func (d *DockerRuntime) VerifyStatus(ctx context.Context, backupID, verificationID string) (string, error)
VerifyStatus returns "" when the verification row does not exist.
type DockerStore ¶
type DockerStore interface {
GetDesiredDatabase(ctx context.Context, name string) (*store.DesiredDatabase, error)
SaveDesiredDatabase(ctx context.Context, d store.DesiredDatabase) error
UpdateDatabaseSuspended(ctx context.Context, name string, suspended bool) error
GetBackupHistory(ctx context.Context, id string) (store.BackupHistory, error)
ListBackupVerifications(ctx context.Context, backupHistoryID string, limit int) ([]store.BackupVerification, error)
ListRunningMajorUpgrades(ctx context.Context) ([]store.MajorUpgrade, error)
ListRestoreHistory(ctx context.Context, databaseName string) ([]store.RestoreHistory, error)
}
DockerStore is the store surface DockerRuntime reads and writes.
type EngineCatalog ¶
type EngineCatalog struct {
Levels []string `json:"levels"`
AutoMax string `json:"auto_max"`
ImageRevert bool `json:"image_revert"`
ManualReason string `json:"manual_reason"`
Notes string `json:"notes"`
Versions []string `json:"versions"`
Lines []SupportLine `json:"lines"`
Advisories []Advisory `json:"advisories"`
}
EngineCatalog is one engine's curated upgrade data.
type Manager ¶
type Manager struct {
Store Store
Runner *Runner
Advisor Advisor
Logger *slog.Logger
Now func() time.Time
// MinWindowRemaining stops a run starting too close to a window's end.
MinWindowRemaining time.Duration
// Unreachable returns why the runner cannot act on a database (for
// example it runs on another node), or "". nil means always reachable.
Unreachable func(db store.DesiredDatabase) string
// contains filtered or unexported fields
}
Manager is the level-triggered controller: every tick it makes sure each unfinished run has a driver and starts runs that are due. It also backs the HTTP API (service.go).
func (*Manager) EffectivePolicy ¶
EffectivePolicy returns the database's own policy, or the platform default with inherited=true.
func (*Manager) SetPolicy ¶
func (m *Manager) SetPolicy(ctx context.Context, name string, p Policy, inherit bool, by string) error
SetPolicy saves a database's policy, or with inherit drops it so the platform default applies again. name may be the platform default.
func (*Manager) UpgradeNow ¶
func (m *Manager) UpgradeNow(ctx context.Context, name, version, by string) (store.DBUpgradeRun, error)
UpgradeNow starts a run immediately, outside any window, with the same backup, verify and revert steps as a scheduled one. Majors are refused.
type NoticeSender ¶
type NoticeSender interface {
SendNotice(ctx context.Context, kind alerting.NotifyKind, notifyURL, text string) error
}
NoticeSender delivers plain text; *alerting.DeployDispatcher satisfies it.
type Overview ¶
type Overview struct {
Database string
Engine string
Version string
Advice Advice
Policy Policy
PolicyInherited bool
WindowOpen bool
NextWindow time.Time
// NextTarget is what the next window would apply, when anything.
NextTarget *Target
Blockers []string
Active *store.DBUpgradeRun
History []store.DBUpgradeRun
}
Overview is everything the Upgrades tab shows for one database.
type Policy ¶
type Policy struct {
AutoUpgrade string `json:"auto_upgrade"`
WindowCron string `json:"window_cron"`
WindowDuration time.Duration `json:"-"`
WindowTimezone string `json:"window_timezone"`
BackupBefore bool `json:"backup_before"`
VerifyAfter bool `json:"verify_after"`
RevertOnFailure bool `json:"revert_on_failure"`
Notify []string `json:"notify"`
}
Policy is a database's automatic upgrade policy, or the platform default.
func DefaultPolicy ¶
func DefaultPolicy() Policy
DefaultPolicy is used when even the platform default row is unreadable.
func PolicyFromStore ¶
func PolicyFromStore(s store.DBUpgradePolicy) Policy
PolicyFromStore converts a stored row.
func (Policy) CanStartAt ¶
CanStartAt reports whether an automatic run may start at now: the window is open and at least minRemaining of it is left.
func (Policy) Validate ¶
Validate checks a policy before it is saved. A window is required once automatic upgrades are on, and a backup before every upgrade is mandatory.
func (Policy) WindowState ¶
WindowState evaluates the policy's window at now. A policy without a window is never open.
type Refresher ¶
Refresher periodically merges newer registry tags into a Catalog. A failed refresh keeps the last good list, so the advisor never loses versions.
type RestoreRunner ¶
type RestoreRunner interface {
RunRestore(ctx context.Context, historyID, databaseName, backupHistoryID, engine, containerName string) error
}
RestoreRunner restores a logical backup into a running database.
type Runner ¶
type Runner struct {
Store Store
Runtime Runtime
Catalog *Catalog
Notifier Notifier
Logger *slog.Logger
Now func() time.Time
// HealthTimeout bounds each wait for the database to come up healthy.
HealthTimeout time.Duration
Poll time.Duration
}
Runner advances one upgrade run through its state machine.
type Runtime ¶
type Runtime interface {
// Busy returns a non-empty reason when another job owns the database.
Busy(ctx context.Context, name string) (string, error)
RunBackup(ctx context.Context, backupID string, db store.DesiredDatabase) error
BackupStatus(ctx context.Context, backupID string) (string, error)
RunVerify(ctx context.Context, verificationID, backupID, engine string) error
VerifyStatus(ctx context.Context, backupID, verificationID string) (string, error)
CheckImage(ctx context.Context, engine, version string) error
ImageDigest(ctx context.Context, name string) (string, error)
// SnapshotData stops the database and copies its data volume into volume; it stays stopped.
SnapshotData(ctx context.Context, name, volume string) error
// SetVersion saves the desired version and makes sure the database runs.
SetVersion(ctx context.Context, name, version string) error
Resume(ctx context.Context, name string) error
// Health reports whether the database runs version and, when deep, answers
// a query. It returns the server's reported version when it has one.
Health(ctx context.Context, db store.DesiredDatabase, version string, deep bool) (ready bool, serverVersion string, err error)
RestoreSnapshot(ctx context.Context, name, volume, version string) error
// ResetData empties the data volume and starts version on it fresh.
ResetData(ctx context.Context, name, version string) error
RestoreBackup(ctx context.Context, restoreID, backupID string, db store.DesiredDatabase) error
RemoveVolume(ctx context.Context, volume string) error
}
Runtime is every side effect a run has on the outside world. Each call is safe to repeat after a restart.
type Store ¶
type Store interface {
GetDesiredDatabase(ctx context.Context, name string) (*store.DesiredDatabase, error)
ListDesiredDatabases(ctx context.Context) ([]store.DesiredDatabase, error)
CreateDBUpgradeRun(ctx context.Context, r store.DBUpgradeRun) error
UpdateDBUpgradeRun(ctx context.Context, r store.DBUpgradeRun) error
GetDBUpgradeRun(ctx context.Context, id string) (store.DBUpgradeRun, error)
ListDBUpgradeRuns(ctx context.Context, databaseName string, limit int) ([]store.DBUpgradeRun, error)
ListActiveDBUpgradeRuns(ctx context.Context) ([]store.DBUpgradeRun, error)
GetDBUpgradePolicy(ctx context.Context, name string) (store.DBUpgradePolicy, bool, error)
SaveDBUpgradePolicy(ctx context.Context, p store.DBUpgradePolicy) error
DeleteDBUpgradePolicy(ctx context.Context, name string) error
}
Store is the persistence the runner and manager need; *store.DB satisfies it.
type SummaryItem ¶
type SummaryItem struct {
Database string
Engine string
Version string
Support string
EOL string
Security bool
Advisories []string
Available int
Active *store.DBUpgradeRun
Last *store.DBUpgradeRun
}
SummaryItem is one database's upgrade status for the attention center.
type SupportLine ¶
SupportLine is one release line and its upstream end-of-life date.
type Target ¶
type Target struct {
Version string `json:"version"`
Kind string `json:"kind"`
Security bool `json:"security"`
// Advisories are the CVE ids this target fixes for the current version.
Advisories []string `json:"advisories,omitempty"`
EOL string `json:"eol,omitempty"`
// Automatic is true when the engine allows this kind without an operator.
Automatic bool `json:"automatic"`
}
Target is one version a database could move to.