Documentation
¶
Overview ¶
Package pgctl runs Postgres-side operations (seeding, readiness) through the runtime driver — pgoverlay never touches data files from the host.
Index ¶
- Constants
- Variables
- func DetectOwner(ctx context.Context, d runtime.Driver, image string) (string, error)
- func Seed(ctx context.Context, d runtime.Driver, s SeedSpec) error
- func SeedDump(ctx context.Context, d runtime.Driver, s SeedDumpSpec) error
- func Settle(ctx context.Context, d runtime.Driver, s SeedSpec) error
- type SeedDumpSpec
- type SeedSpec
- type SettleMode
Constants ¶
const ConnectTimeout = 10 * time.Second
ConnectTimeout bounds every libpq connection attempt the seed helpers make to the source (PGCONNECT_TIMEOUT), so a wrong address or a firewall that drops packets fails in seconds instead of hanging until the OS gives up.
const DefaultOwner = "999:999"
DefaultOwner is the postgres user of the official Debian-based images, used when SeedSpec.Owner is empty. The Alpine images use 70:70.
const DefaultSSLMode = "prefer"
DefaultSSLMode is libpq's own default: TLS when the server offers it, without certificate verification, falling back to plaintext. Managed providers reached over the internet warrant require or verify-full.
const DefaultSettleMode = SettleFreeze
DefaultSettleMode applies when a SeedSpec leaves Settle empty.
const SSLModeEnv = "PGOVERLAY_SEED_SSLMODE"
SSLModeEnv is the environment variable (of branchd, or of pgb without --server) that sets the libpq sslmode for source connections when a SeedSpec leaves SSLMode empty. DefaultSSLMode applies when it is unset.
const SettleEnv = "PGOVERLAY_SEED_SETTLE"
SettleEnv is the environment variable that sets the settle mode: pgb reads it in local mode, branchd uses it as the --seed-settle default.
Variables ¶
var ErrInvalidSpec = errors.New("invalid seed spec")
ErrInvalidSpec marks a seed request that cannot succeed as given: no host, a port out of range, an unknown sslmode. Callers reject it before any state is created (the API answers 400).
var ErrSeedFailed = errors.New("seed command failed")
ErrSeedFailed marks a failure of the seed command itself (pg_basebackup, or the pg_dump | psql pipeline) as opposed to the runtime plumbing around it. Such a failure is almost always caused by the source's configuration (wrong password, no pg_hba entry, unreachable host, missing privilege) and its message carries the tool's own output, which never includes the password (it travels only in the helper's environment). Test with errors.Is.
var ErrVersionMismatch = errors.New("source PostgreSQL major version does not match the branch image")
ErrVersionMismatch reports a seeded cluster whose major version differs from the branch image's: Postgres refuses to start on it, so every branch would fail.
Functions ¶
func DetectOwner ¶
DetectOwner asks image for the uid and gid of its postgres user, which the official images do not agree on: 999:999 in the Debian ones, 70:70 in the Alpine ones; custom images may use anything. Seeding writes the cluster as that user (SeedSpec.Owner), because the image's postgres runs as it in every branch. An image without a postgres user cannot be seeded or branched: that is an ErrSeedFailed naming the image. Output that does not parse (it never should) returns "", which keeps the Debian identity.
func Seed ¶
Seed runs pg_basebackup into the source volume. The helper runs as the image's postgres user (SeedSpec.Owner, 999:999 when unset) so file ownership matches branch containers. Data lands in <volume>/data because pg_basebackup insists on creating the target dir itself with 0700; the volume root is first chowned to that user so it can. Requires REPLICATION privilege on the source (superuser works).
A standby works as a source: its recovery state is removed from the copy (basebackupFixupScript) so branches start as independent, writable primaries. The copy's major version must match the image's, which is checked here rather than 90 seconds into every branch's readiness wait.
func SeedDump ¶
SeedDump builds the source volume from a logical dump: initdb a fresh cluster, then pg_dump | psql from the remote — all inside one helper container running as the image's postgres user (SeedSpec.Owner), so file ownership matches branch containers. Unlike Seed it needs only a normal user on the remote (no REPLICATION privilege), which makes managed providers usable as sources. The helper image's major version must be >= the remote server's (pg_dump cannot dump newer servers) and branches run the cluster initdb produced, i.e. the helper image's version.
func Settle ¶
Settle prepares a pg_basebackup seed for branching, in a helper on the branch image running as the in-image postgres user: it starts postgres on the seed once, which completes the base backup's recovery, runs VACUUM (FREEZE, ANALYZE) on every database (SettleFreeze), and stops it with a clean shutdown checkpoint. Branches then start without crash recovery, and a read in a branch no longer writes (no hint bits to set, nothing to prune, no anti-wraparound autovacuum), so on the overlay backend it copies nothing. See settleScript for how a production configuration is made safe to start.
SettleOff does nothing. A seed from SeedDump needs no Settle: its helper already ends with a clean shutdown and applies SettleFreeze itself.
The seed is an independent copy; the source is never touched. A failure to start, stop or verify the cluster is an error (tagged ErrSeedFailed: the usual cause is the source's configuration, and every branch would fail the same way); a failed VACUUM is logged and the seed kept.
Types ¶
type SeedDumpSpec ¶
type SeedDumpSpec struct {
SeedSpec
Database string // remote database to dump ("" = postgres)
Schemas []string // schemas to dump (empty = the whole database)
}
SeedDumpSpec seeds a source with pg_dump instead of pg_basebackup: a logical copy for managed Postgres (Supabase, Neon, RDS, Cloud SQL) where physical replication connections are not allowed.
func (SeedDumpSpec) Validate ¶
func (s SeedDumpSpec) Validate() error
Validate checks the connection settings and the schema patterns. A pattern must not contain a comma: the registry stores the list comma-joined, so a refresh would split it into two patterns.
type SeedSpec ¶
type SeedSpec struct {
Image string // postgres image matching the source's major version
// Volume is the seed target: a volume name, or — with MountKind
// MountHostPath (zfs backend) — the dataset's absolute mountpoint.
Volume string
MountKind runtime.MountKind
Network string // docker network from which the source is reachable ("" = bridge)
Host string
Port int
User string
Password string
// SSLMode is the libpq sslmode for the source connection ("" =
// $PGOVERLAY_SEED_SSLMODE, else DefaultSSLMode).
SSLMode string
// Settle is how the seeded cluster is prepared before any branch starts
// from it ("" = DefaultSettleMode). Seed leaves the cluster as
// pg_basebackup wrote it and the caller runs Settle next; SeedDump
// applies the mode inside its own helper.
Settle SettleMode
// Owner is the numeric "uid:gid" of the postgres user in Image (see
// DetectOwner): the seed volume is chowned to it and every seed helper
// runs as it, so the files belong to the user the image's postgres runs
// as. "" keeps the official Debian images' identity: the volume is
// chowned to 999:999 and helpers run as the user named postgres.
Owner string
}
type SettleMode ¶
type SettleMode string
SettleMode is how a freshly seeded cluster is prepared before any branch starts from it (branchd --seed-settle, pgb $PGOVERLAY_SEED_SETTLE).
A pg_basebackup copy is an online backup: every branch that starts from it replays the WAL streamed during the backup, and the copied pages carry whatever hint bits, dead tuples and unfrozen xids the source had. Each of those turns a read in a branch into a write (backup-label replay, hint-bit setting, HOT pruning, anti-wraparound autovacuum), and on the overlay backend a write copies the touched file into the branch. Settling does that work once, in the seed, so branches start from a clean shutdown and their reads write nothing.
const ( // SettleFreeze recovers the seed, runs VACUUM (FREEZE, ANALYZE) on every // database and shuts it down cleanly. The default. SettleFreeze SettleMode = "freeze" // SettleRecover recovers the seed and shuts it down cleanly, without // the VACUUM: branches skip WAL replay but may still set hint bits. SettleRecover SettleMode = "recover" // SettleOff leaves the seed exactly as the seed command wrote it (the // behaviour before settling existed). SettleOff SettleMode = "off" )
func ParseSettleMode ¶
func ParseSettleMode(s string) (SettleMode, error)
ParseSettleMode validates a settle mode; "" is DefaultSettleMode.