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

coreupdate

package
v0.4.26 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package coreupdate defines the provider-neutral, fail-closed Core update plan. Runtime mutation is injected through the existing Core/provider lifecycle.

Index

Constants

This section is empty.

Variables

View Source
var ErrDCSInvalidEvidence = errors.New("invalid etcd DCS recovery evidence")
View Source
var ErrDCSUnsupported = errors.New("UNSUPPORTED: durable etcd DCS snapshot and verified restore adapter unavailable")

Functions

func AwaitPatroniQuorum

func AwaitPatroniQuorum(ctx context.Context, expectedLeader string, interval time.Duration, inspect func(context.Context) ([]PatroniMemberState, error)) (string, error)

AwaitPatroniQuorum waits only for known healthy standbys to replay WAL. Unknown state, split brain, inspection failure or a changed expected leader is never treated as transient. Callers must supply a bounded context.

func Execute

func Execute(ctx context.Context, plan Plan, hooks Hooks) error

func ExecuteJournaled

func ExecuteJournaled(ctx context.Context, plan Plan, journalPath string, hooks Hooks) error

ExecuteJournaled runs an already validated release plan against a durable per-realization journal. An interrupted apply is NEVER skipped: a resumed attempt must re-run provider-native idempotent reconciliation and verification. A verified step is also re-verified before it can be skipped, preventing stale disk state from being mistaken for a live ready provider.

func JournalKey

func JournalKey(d Delta) string

func PrepareAndRollPatroniCluster

func PrepareAndRollPatroniCluster(ctx context.Context, gate PatroniSwitchoverGate, dcs DCSRecoveryAdapter, installation, target, cluster, release string, maxLag int64) error

PrepareAndRollPatroniCluster is the central handoff for Session 1B. It obtains a fresh DCS snapshot through the injected adapter, verifies its identity and restore viability, and only then enters the native mutation state machine. A nil/unavailable adapter stops before any member action.

func ResolveOwnedServiceVolume

func ResolveOwnedServiceVolume(path, service, project string) (string, error)

ResolveOwnedServiceVolume validates the actual Compose service data mount. No guessed named volume or host bind directory is accepted for recovery.

func RestorePostgresBasebackup

func RestorePostgresBasebackup(ctx context.Context, point StreamRecoveryPoint, major, destination string) error

RestorePostgresBasebackup materializes the complete immutable physical archive in a NEW isolated directory. It never replaces a live PGDATA and never claims SQL startup, WAL replay or DCS cutover acceptance. An interrupted directory is deliberately preserved and cannot be blindly overwritten.

func RewriteOwnedComposeImages

func RewriteOwnedComposeImages(source []byte, mutations map[string]Delta) ([]byte, error)

RewriteOwnedComposeImages patches only precisely listed, BaseHarbor-owned provider services. It leaves every unrelated provider and field untouched.

func RewriteOwnedSpiloImages

func RewriteOwnedSpiloImages(input []byte, previous, desired BackingPin) ([]byte, error)

RewriteOwnedSpiloImages applies the same immutable image to exactly three known managed PostgreSQL members. Unknown current images fail closed.

func RollPatroniCluster

func RollPatroniCluster(ctx context.Context, gate PatroniSwitchoverGate, dcs DCSRecoveryAdapter, evidence DCSRecoveryEvidence, installation, target, cluster, release string, maxLag int64) error

RollPatroniCluster requires both data and DCS recovery evidence before ANY mutation. It rolls replicas, explicitly switches leadership, then reconciles the old primary as a replica. An ambiguous switchover is never retried blindly.

func RollPatroniMembers

func RollPatroniMembers(ctx context.Context, gate PatroniRollingGate, maxLag int64) error

RollPatroniMembers performs a replica-first replacement. There is no automatic leadership switch: changing the current primary is unsupported unless a separate, verified switchover contract has been supplied. Every step is rechecked before mutation and journaled before/after.

func RollPatroniMembersResumable

func RollPatroniMembersResumable(ctx context.Context, gate PatroniRollingResume, maxLag int64) error

RollPatroniMembersResumable runs only replica steps. Verified entries are always live-reverified. In-progress entries require explicit recovery first. The primary still requires a separate, proved switchover contract.

func RunMixedProviderUpdates

func RunMixedProviderUpdates(ctx context.Context, plan Plan, journalPath string, ops NativeProviderOps, assets map[string]NativeProviderAssets, bound Hooks, useBound func(Delta) bool) error

RunMixedProviderUpdates keeps one durable ExecuteJournaled transaction while delegating OpenBao/Keycloak lifecycle work to their bound provider adapters. SQL/backing deltas continue to use the native volume/Compose recovery path.

func RunNativeProviderUpdates

func RunNativeProviderUpdates(ctx context.Context, plan Plan, journalPath string, ops NativeProviderOps, assets map[string]NativeProviderAssets) error

RunNativeProviderUpdates wires immutable provider-volume recovery, atomic pinned Compose staging, provider-native lifecycle and semantic verification into the durable journal. A missing hook or per-provider asset fails before the first provider is touched.

func RunVerifiedDCSCutover

func RunVerifiedDCSCutover(ctx context.Context, adapter DCSRecoveryAdapter, evidence DCSRecoveryEvidence, installation, target, cluster, release string, ops DCSCutoverOps, journal DCSCutoverJournal) error

RunVerifiedDCSCutover MUST only run after PostgreSQL physical recovery and immutable DCS snapshot validation. A resumed 'prepared' state is ambiguous: an interrupted fence may already be active, so require operator recovery. A resumed 'fenced' state cannot activate without observed fencing.

func StageAndRollPatroniCluster

func StageAndRollPatroniCluster(ctx context.Context, gate PatroniSwitchoverGate, dcs DCSRecoveryAdapter, dcsCheckpoint DCSCheckpoint, images HAPostgresComposeCheckpoint, installation, target, cluster, release string, maxLag int64) error

StageAndRollPatroniCluster is the durable high-availability coordinator. A streaming PostgreSQL backup is verified before obtaining DCS evidence; both recovery artifacts precede atomic, idempotent Compose staging, and only then may individual native Patroni members be reconciled.

func VerifyDCSEvidence

func VerifyDCSEvidence(ctx context.Context, adapter DCSRecoveryAdapter, evidence DCSRecoveryEvidence, installation, target, cluster, release string) error

func VerifyPatroniQuorum

func VerifyPatroniQuorum(ctx context.Context, members []PatroniMemberState, maxReplayLag int64) (string, []string, error)

VerifyPatroniQuorum checks a complete three-member HA snapshot before a database upgrade may be considered. It deliberately does not authorize an image mutation: a durable logical/physical backup and provider-native rolling lifecycle are additional independent requirements.

func VerifyPostgresBasebackup

func VerifyPostgresBasebackup(p StreamRecoveryPoint, major string) error

VerifyPostgresBasebackup verifies that the immutable native backup is a plausible single-tablespace PostgreSQL tar archive for the pinned major. A valid tar alone is NOT evidence that a restore has succeeded.

func VerifyPostgresBasebackupRestore

func VerifyPostgresBasebackupRestore(ctx context.Context, point StreamRecoveryPoint, major, destination string) error

VerifyPostgresBasebackupRestore permits replay only when every isolated file still matches the original physical archive. Partial, changed or extra files never authorize activation or another extraction over existing data.

func WaitForPatroniQuorum

func WaitForPatroniQuorum(ctx context.Context, gate PatroniRollingGate, expectedLeader string, maxLag int64, timeout time.Duration) error

WaitForPatroniQuorum tolerates bounded startup/readiness delays after a single member restart. Any *valid* unexpected leader is treated as drift rather than silently waited out. No additional mutation can proceed until all three members and replay lag satisfy the HA contract again.

Types

type BackingPin

type BackingPin struct {
	Role    string `json:"role"`
	Version string `json:"version"`
	Image   string `json:"image"`
	Digest  string `json:"digest"`
}

BackingPin identifies durable backing databases owned by a Core reference provider, without misclassifying them as optional core capabilities.

type BoundProviderRegistry

BoundProviderRegistry is implemented by providerbinding.Registry. Native implementation hooks and ownership checks are constructed by Core; this coordinator never creates unverified provider backup or identity fixtures.

type BoundProviderTransaction

type BoundProviderTransaction struct {
	Registry        BoundProviderRegistry
	BackupDirectory string
	RecordExternal  func(context.Context, Delta, string) error
}

BoundProviderTransaction connects the Session 1C adapters to the existing ExecuteJournaled lifecycle, including durable per-provider backup references.

func (BoundProviderTransaction) Hooks

func (t BoundProviderTransaction) Hooks() Hooks

Hooks provides the only adapter execution integration points to the central Core journal. The caller MUST supply a prepared owned registry and private journal directory, then use ExecuteJournaled with these hooks.

type Classification

type Classification string
const (
	NoChange          Classification = "no_change"
	SafeReconcile     Classification = "safe_reconcile"
	BackupRequired    Classification = "backup_recovery_required"
	MigrationRequired Classification = "migration_required"
	Unsupported       Classification = "unsupported"
)

type ComposeCheckpoint

type ComposeCheckpoint struct {
	Path      string
	Directory string
}

ComposeCheckpoint makes the on-disk image update reversible after an already verified provider backup was captured. It cannot replace recovery of data volumes; callers must pair it with a native provider recovery point.

func (ComposeCheckpoint) Capture

func (c ComposeCheckpoint) Capture(mutations map[string]Delta) error

Capture preserves the original image realization together with a native database backup, without applying the upgrade. Recovery remains possible even when another journal subsequently performs the provider mutation.

func (ComposeCheckpoint) Restore

func (c ComposeCheckpoint) Restore(mutations map[string]Delta) error

Restore returns to the exact original provider declarations when the runtime has been quiesced and data has been recovered by a provider-native hook.

func (ComposeCheckpoint) Stage

func (c ComposeCheckpoint) Stage(mutations map[string]Delta) error

Stage preserves the original Compose atomically before writing the new, immutable image-pinned realization. A replay verifies the prior checkpoint rather than creating a second backup from possibly mutated Compose.

type DCSCheckpoint

type DCSCheckpoint struct{ Path string }

DCSCheckpoint binds a validated backup to the exact upgrade transaction. On resume it verifies the prior artifact instead of silently replacing it with a new snapshot from an already partially mutated cluster.

func (DCSCheckpoint) Acquire

func (c DCSCheckpoint) Acquire(ctx context.Context, adapter DCSRecoveryAdapter, installation, target, cluster, release string) (DCSRecoveryEvidence, error)

type DCSCutoverJournal

type DCSCutoverJournal struct {
	Path string
	// contains filtered or unexported fields
}

DCSCutoverJournal stores the last durable phase in a protected Core state directory. A failed or ambiguous phase remains fenced and MUST NOT restore the previous DCS automatically, avoiding concurrent DCS primaries.

type DCSCutoverOps

type DCSCutoverOps interface {
	FenceOldDCS(context.Context) error
	VerifyFenced(context.Context) error
	ActivateIsolated(context.Context, DCSRecoveryEvidence) error
	VerifyNewQuorum(context.Context, DCSRecoveryEvidence) error
	VerifyPatroniDCS(context.Context) error
	CommitCutover(context.Context, DCSRecoveryEvidence) error
}

DCSCutoverOps separates old-cluster fencing, isolated snapshot activation, and new-cluster/Patroni readiness. Each method must be an idempotent native RuntimeProvider action; no Compose project-wide stop is allowed.

type DCSRecoveryAdapter

type DCSRecoveryAdapter interface {
	Snapshot(context.Context) (DCSRecoveryEvidence, error)
	Validate(context.Context, DCSRecoveryEvidence) error
	VerifyRestorable(context.Context, DCSRecoveryEvidence) error
	Restore(context.Context, DCSRecoveryEvidence) error
}

DCSRecoveryAdapter is supplied by Session 1B. Core orchestration owns sequencing and never substitutes a live volume copy for etcd snapshotting.

type DCSRecoveryEvidence

type DCSRecoveryEvidence struct {
	Installation string
	Target       string
	Cluster      string
	Release      string
	SnapshotID   string
	SHA256       string
}

DCSRecoveryEvidence is the minimum cross-session contract with the etcd adapter (Session 1B). Its identity must be bound to the managed installation, target, cluster and release. SHA256 covers the complete immutable snapshot bytes.

func CaptureAndVerifyDCS

func CaptureAndVerifyDCS(ctx context.Context, adapter DCSRecoveryAdapter, installation, target, cluster, release string) (DCSRecoveryEvidence, error)

CaptureAndVerifyDCS delegates snapshot creation exclusively to Session 1B. No cluster mutation is authorized until the same artifact is both validated and independently checked for restorable content.

type Delta

type Delta struct {
	Installed      Realization    `json:"installed"`
	Desired        Desired        `json:"desired"`
	Classification Classification `json:"classification"`
	Reason         string         `json:"reason,omitempty"`
}

func ClassifyHAPostgresPin

func ClassifyHAPostgresPin(installed Realization, pin BackingPin) Delta

ClassifyHAPostgresPin binds the running Spilo/Patroni database to its release-owned HA image identity. A matching tag without a matching immutable digest is never sufficient evidence to replace or restart a data-bearing member. PostgreSQL HA image changes remain unsupported until the cluster migration and durable recovery contract has explicit runtime evidence.

type Desired

type Desired struct {
	Kind    ProviderKind `json:"kind"`
	Image   string       `json:"image"`
	Digest  string       `json:"digest"`
	Version string       `json:"version"`
}

type EtcdBootProbe

type EtcdBootProbe struct {
	Binary           string
	Endpoints        []string
	TLS              etcdbackup.TLSFiles
	VerifyPatroniDCS func(context.Context) error
}

EtcdBootProbe requires a separately booted isolated recovery cluster. The snapshot itself is not evidence that etcd can form quorum.

func (EtcdBootProbe) Verify

type EtcdDCSBridge

type EtcdDCSBridge struct {
	Store             etcdbackup.Store
	Restorer          etcdbackup.Restorer
	RecoveryDirectory string
	Release           string
	// VerifyRecoveredCluster must attest isolated etcd startup, authenticated
	// cluster identity, quorum and Patroni DCS readiness. File presence is insufficient.
	VerifyRecoveredCluster func(context.Context, etcdbackup.Identity, etcdbackup.SnapshotInfo) error
	// LiveRestore is bound only by an explicit, lifecycle-locked recovery
	// request. Ordinary snapshot validation never authorizes live replacement.
	LiveRestore func(context.Context, DCSRecoveryEvidence) error
}

EtcdDCSBridge adapts the isolated Session 1B snapshot/restore store to the central Core journal. The restore destination must be a new, isolated path: this bridge never replaces a live etcd member's data directory.

func (*EtcdDCSBridge) Restore

func (*EtcdDCSBridge) Snapshot

func (*EtcdDCSBridge) Validate

func (b *EtcdDCSBridge) Validate(ctx context.Context, ev DCSRecoveryEvidence) error

func (*EtcdDCSBridge) VerifyRestorable

func (b *EtcdDCSBridge) VerifyRestorable(ctx context.Context, ev DCSRecoveryEvidence) error

type HAPostgresComposeCheckpoint

type HAPostgresComposeCheckpoint struct {
	Path      string
	Directory string
	Previous  BackingPin
	Desired   BackingPin
}

HAPostgresComposeCheckpoint manages only the three owned Spilo member image declarations. It does not restart services or authorize a DB migration.

func (HAPostgresComposeCheckpoint) Stage

Stage is crash-safe and idempotent. The recovery point and DCS evidence must already be verified by the caller before invoking it.

type Hooks

type Hooks struct {
	Preflight     func(context.Context, Plan) error
	RecoveryPoint func(context.Context, Delta) error
	Recover       func(context.Context, Delta, string) error // mandatory for resuming interrupted mutation
	Apply         func(context.Context, Delta) error
	Verify        func(context.Context, Delta) error
	Record        func(context.Context, Delta, string) error
}

type Journal

type Journal struct {
	Release string            `json:"release"`
	Steps   map[string]string `json:"steps"`
}

Journal stores per-realization progress after each successful transition. A prior failed or in-progress mutation must be reconciled explicitly rather than treated as a verified update on resume.

func LoadJournal

func LoadJournal(path, release string) (Journal, error)

func (*Journal) Record

func (j *Journal) Record(path string, d Delta, state string) error

type NativeProviderAssets

type NativeProviderAssets struct {
	Recovery VolumeRecovery
	Compose  ComposeCheckpoint
}

func (NativeProviderAssets) Recover

Recover restores the verified owned volume and original image before native reconciliation and semantic checks. Both native transaction drivers use it.

type NativeProviderOps

type NativeProviderOps interface {
	Preflight(context.Context, Plan) error
	Quiesce(context.Context, Delta) error
	ReconcilePinned(context.Context, Delta) error
	ReconcileOriginal(context.Context, Delta) error
	VerifySemantics(context.Context, Delta) error
	Record(context.Context, Delta, string) error
}

NativeProviderOps holds provider-specific lifecycle operations (PostgreSQL, OpenBao and Keycloak). It never guesses database quiescence or OIDC readiness.

type PatroniMemberJournal

type PatroniMemberJournal struct {
	Path         string
	Release      string
	Installation string
	Scope        string
	Desired      Desired
}

PatroniMemberJournal stores each member's progress in the existing, fsync-backed and release-bound Core journal. A new desired image pin generates distinct keys, preventing stale verified steps from being reused.

func (PatroniMemberJournal) Record

func (j PatroniMemberJournal) Record(ctx context.Context, name, state string) error

func (PatroniMemberJournal) StepState

func (j PatroniMemberJournal) StepState(ctx context.Context, name string) (string, error)

type PatroniMemberState

type PatroniMemberState struct {
	Name      string
	Primary   bool
	Replica   bool
	ReplayLag int64
	Healthy   bool
}

PatroniMemberState is a verified, non-secret snapshot from Patroni's /primary and /replica endpoints. Unknown members must never be inferred.

type PatroniRollingGate

type PatroniRollingGate interface {
	VerifyRecovery(context.Context) error
	Inspect(context.Context) ([]PatroniMemberState, error)
	Recreate(context.Context, string) error
	VerifyMemberImage(context.Context, string) error
	Record(context.Context, string, string) error
}

PatroniRollingGate deliberately separates a verified backup from permission to mutate cluster members. The implementation must be backed by durable physical PostgreSQL AND DCS recovery artifacts, proven before any action.

type PatroniRollingResume

type PatroniRollingResume interface {
	PatroniRollingGate
	StepState(context.Context, string) (string, error)
	RecoverInterrupted(context.Context, string, string) error
}

PatroniRollingResume extends the runtime gate with a durable per-member state lookup. A pending mutation cannot be replayed blindly: it must be reconciled and verified independently by the provider implementation.

type PatroniSwitchoverGate

type PatroniSwitchoverGate interface {
	PatroniRollingResume
	Switchover(context.Context, string, string) error
}

PatroniSwitchoverGate supplies the one missing native transition after all replicas have been individually upgraded and their image digests verified. Native switchover must be compare-and-set against the observed leader.

type Plan

type Plan struct {
	Release string  `json:"release"`
	Deltas  []Delta `json:"deltas"`
}

func Build

func Build(release string, installed []Realization, desired []Desired) (Plan, error)

type ProviderKind

type ProviderKind string
const (
	SQL      ProviderKind = "sql"
	Secrets  ProviderKind = "secrets"
	Identity ProviderKind = "identity"
)

type Realization

type Realization struct {
	Kind         ProviderKind `json:"kind"`
	Installation string       `json:"installation"`
	Scope        string       `json:"scope"`
	Instance     string       `json:"instance"`
	Owner        string       `json:"owner"`
	Image        string       `json:"image"`
	Digest       string       `json:"digest"`
	Version      string       `json:"version"`
}

type ReleaseManifest

type ReleaseManifest struct {
	Release   string       `json:"release"`
	Providers []Desired    `json:"providers"`
	Backing   []BackingPin `json:"backing"`
}

func LoadRelease

func LoadRelease(version string) (ReleaseManifest, error)

LoadRelease resolves only digests compiled into the selected BaseHarbor binary. A missing release must fail; no mutable OCI tag fallback is allowed.

type StreamRecoveryPoint

type StreamRecoveryPoint struct {
	Directory string
	Name      string
}

StreamRecoveryPoint stores a provider-native backup without buffering a potentially multi-gigabyte PostgreSQL stream in process memory. The caller must supply a database-consistent source; volume exports from live writers are not valid inputs. A completed file and checksum are immutable on replay.

func (StreamRecoveryPoint) Capture

func (p StreamRecoveryPoint) Capture(ctx context.Context, source func(context.Context, io.Writer) error) error

func (StreamRecoveryPoint) OpenVerified

func (p StreamRecoveryPoint) OpenVerified() (*os.File, error)

OpenVerified opens the immutable backup only after checksum, ownership and regular-file validation. Callers must close the returned handle.

func (StreamRecoveryPoint) Verify

func (p StreamRecoveryPoint) Verify() error

type VolumeRecovery

type VolumeRecovery struct {
	Runtime   VolumeSnapshotRuntime
	Directory string
	Project   string
	Volume    string
	// VerifyQuiesced proves no database writer can mutate this volume during an archive/restore.
	VerifyQuiesced func(context.Context, string, string) error
}

func (VolumeRecovery) Capture

func (v VolumeRecovery) Capture(ctx context.Context, delta Delta) error

Capture persists an owner-only recovery point and its SHA-256 checksum. It deliberately rejects pre-existing recovery points rather than overwriting a backup from an earlier interrupted migration.

func (VolumeRecovery) Recover

func (v VolumeRecovery) Recover(ctx context.Context, delta Delta) error

Recover validates the immutable recovery archive before restoring the *owned* runtime volume; if verification fails it never touches a volume.

type VolumeSnapshotRuntime

type VolumeSnapshotRuntime interface {
	ExportOwnedVolume(context.Context, string, string) ([]byte, error)
	RestoreOwnedVolume(context.Context, string, string, []byte) error
}

VolumeSnapshotRuntime provides the existing Docker/Podman owned-volume export/restore contract without allowing this package to shell out.

Jump to

Keyboard shortcuts

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