Help us shape the future of Go! Take the 2026 Go Developer Survey

migrator

package
v0.5.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package migrator applies the Dexaflow SQL migrations with golang-migrate over pgx v5 and turns the driver's errors into messages that name the cause, the remedy and the chart value involved (#1020).

It is what the migrate image runs (cmd/dexaflow-migrate) for the Helm chart's pre-install and pre-upgrade hook Job. Before it, the image shipped golang-migrate's own CLI, which linked lib/pq while the control plane and Lite use pgx, and printed the raw driver error: `pq: database "x" does not exist` on a fresh install, with nothing saying that database.url is a chart value or that Dexaflow does not create the database. ADR 0090 builds the installation id and the opt-in self-migration on top of this package.

Exit codes split deterministic failures from transient ones, so the chart's podFailurePolicy can fail the Job at once on a missing database or a wrong password instead of retrying it three times (see DeterministicExitCodes).

Index

Constants

View Source
const (
	// ExitFailed is an unrecognized failure, retried by the Job.
	ExitFailed = 1
	// ExitUsage is a command line the wrapper cannot run.
	ExitUsage = 2
	// ExitBadDSN is a database.url that is not a Postgres URL.
	ExitBadDSN = 3
	// ExitMissingDatabase is a database that does not exist on the server.
	ExitMissingDatabase = 4
	// ExitAuth is a refused user or password.
	ExitAuth = 5
	// ExitMissingCA is a missing sslrootcert file.
	ExitMissingCA = 6
	// ExitDirty is a dirty schema, which needs a person.
	ExitDirty = 7
	// ExitReplaced is a database that is not this release's own, which needs
	// a person to restore the right one or accept this one.
	ExitReplaced = 8
	// ExitTransient is a failure worth retrying: a server not reachable yet,
	// not accepting connections, or another migration holding the lock. It is
	// EX_TEMPFAIL from sysexits.h.
	ExitTransient = 75
)

Exit codes. The deterministic ones (see DeterministicExitCodes) are the failures a retry cannot fix; the chart fails the Job on them at once.

View Source
const InstallationIDKey = "installationId"

InstallationIDKey is the ConfigMap key that holds the installation id. The chart's Deployments read it into LEOFLOW_DATABASE_INSTALLATION_ID (database.installation_id).

Variables

This section is empty.

Functions

func DeterministicExitCodes

func DeterministicExitCodes() []int

DeterministicExitCodes are the exit codes a retry cannot change. The chart's migration Job lists the same set in its podFailurePolicy (a test keeps the two equal).

func DriverURL

func DriverURL(dsn string) string

DriverURL rewrites a postgres:// or postgresql:// DSN to golang-migrate's pgx5:// scheme, so the migration runs on pgx like the control plane does and a DSN that starts the server also migrates (sslrootcert=system is pgx-only, and the lib/pq CLI failed on it).

func Main

func Main(ctx context.Context, args []string, stdout, stderr io.Writer, version string) int

Main runs the command line the migrate image takes and returns the process exit code. Failures are printed to stderr in two lines: what happened and what to do, then the driver's own error, which the docs quote.

func PreflightCA

func PreflightCA(t Target) error

PreflightCA checks, before any dial, that the sslrootcert file the DSN names is present. Without it pgx fails with `unable to read CA file`, which says nothing about the ConfigMap the chart mounts there. A Helm-side check cannot do this: lookup returns nothing under helm template, --dry-run and Argo CD.

func Up

func Up(ctx context.Context, dsn string, log io.Writer) error

Up applies the migrations embedded in this binary to the database at dsn, as the image's `up` does, and returns nil or a *Failure. It is what the server runs in-process for migrations.onBoot (ADR 0090 decision 4), so self-migration and the hook Job share one code path, one set of failure messages and golang-migrate's advisory lock, which serializes them. It neither reads nor writes the installation id: only the Job, which owns the ConfigMap, records it.

Types

type Failure

type Failure struct {
	// Kind is the class of the failure.
	Kind Kind
	// Code is the exit code the process ends with.
	Code int
	// Summary names the cause and the remedy.
	Summary string
	// Cause is the underlying error, nil when the wrapper produced it.
	Cause error
}

Failure is a classified migration error: its kind, the process exit code, and a message in the chart's terms. Cause is the driver error it came from.

func Classify

func Classify(err error, t Target) *Failure

Classify maps an error from opening the database or running a command to a Failure. A Failure already in the chain is returned as is. Classify(nil) is nil.

func (*Failure) Error

func (f *Failure) Error() string

Error is the summary; the cause is printed on its own line by Main.

func (*Failure) Unwrap

func (f *Failure) Unwrap() error

Unwrap returns the driver error, so callers can errors.Is it.

type Kind

type Kind int

Kind names the class of a migration failure.

const (
	// KindOther is an error the wrapper does not recognize; it is retried.
	KindOther Kind = iota
	// KindUsage is a command line the wrapper cannot run.
	KindUsage
	// KindBadDSN is a database.url that is not a Postgres URL.
	KindBadDSN
	// KindMissingDatabase is a server without the database the DSN names.
	KindMissingDatabase
	// KindAuth is a server that refused the DSN's user or password.
	KindAuth
	// KindMissingCA is an sslrootcert path with no file behind it.
	KindMissingCA
	// KindDirty is a schema_migrations row left dirty by an interrupted file.
	KindDirty
	// KindUnreachable is a server that could not be reached or is not
	// accepting connections yet.
	KindUnreachable
	// KindLocked is another migration holding golang-migrate's lock.
	KindLocked
	// KindReplaced is a database that is not the one this release was
	// installed on (ADR 0090 decision 3): emptied, restored from another
	// installation, or repointed.
	KindReplaced
)

The failure kinds. Each maps to one exit code.

func (Kind) String

func (k Kind) String() string

String is the kind's name, for logs and test output.

type Target

type Target struct {
	// Host is the host name or address of the Postgres server.
	Host string
	// Port is the TCP port, 5432 when the DSN names none.
	Port string
	// Database is the database name from the DSN's path.
	Database string
	// User is the role the DSN connects as.
	User string
	// SSLRootCert is the sslrootcert parameter, empty when absent.
	SSLRootCert string
	// contains filtered or unexported fields
}

Target is what the messages say about the database the DSN points at. It is parsed from the DSN once, before any connection, and never carries the password into a message.

func ParseTarget

func ParseTarget(dsn string) (Target, error)

ParseTarget reads the parts of a DSN the messages need. A DSN that is not a Postgres URL with a database name is a KindBadDSN failure, whose text never quotes the DSN, since it holds the password.

func (Target) Address

func (t Target) Address() string

Address is host:port in the form a message prints it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL