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

instancebackup

package
v1.0.0-rc.12 Latest Latest
Warning

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

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

Documentation

Overview

Package instancebackup is a whole-AppTown backup and restore (stock/docs/guides/apptown-backups.md): one archive, encrypted with a passphrase, holding the built-in database's dump, the data directory (without pgdata and cache, with the deployment backups kept on disk) and a manifest; and its restore onto a fresh host, where each built-in deployment is filled from its own newest whole set.

It composes owners and owns no table: data protection names each deployment's newest whole set, keeps the backup-file lock, moves the records of sets kept on disk, records the fills and copies an archive to the backup store; deployment lists the built-in host's deployments and holds those a restore must not act on; secret says whether an external store keeps values; the composition root makes the built-in database and dumps the database AppTown runs on, in a pg_dump container of the server's major (BuiltinDatabase, databaseDump).

The running AppTown takes a backup, asked through its control socket by `apptownd backup` (control.go), because only it can hold its own new work (Hold). No app is stopped for it. A restore runs before the restored AppTown first starts (restore.go).

Index

Constants

View Source
const (
	ArchiveFormat  = "apptown-backup"
	ArchiveVersion = 1
)

ArchiveFormat names a whole-AppTown archive's manifest.

Variables

View Source
var ErrBackupUnderWay = errors.New("a backup of AppTown is already under way")

ErrBackupUnderWay refuses a second backup while one runs.

Functions

func CompleteRestore

func CompleteRestore(dataDir string, pending *PendingRestore) error

CompleteRestore requires the caller's exclusive daemon/data ownership lock and successful layout repair plus AfterRestore. The digest detects changed evidence; it is not a lock-free compare-and-delete primitive.

func ControlSocketPath

func ControlSocketPath(dataDir string) string

ControlSocketPath is where a data directory's control socket is.

Types

type AfterRestoreReport

type AfterRestoreReport struct {
	Relocated int64    `json:"relocated"` // sets kept on disk whose records moved to this data directory
	Held      []string `json:"held"`      // App Platform and Portainer deployments to be checked
	Filling   []string `json:"filling"`   // built-in deployments rebuilt with their newest set on disk
	NotFilled []string `json:"notFilled"` // built-in deployments whose data needs a person, with why
	NoBackup  []string `json:"noBackup"`  // built-in deployments with no whole set: not held, so a rebuild has no restored data
}

AfterRestoreReport is what a restore left for the restored AppTown's first start.

type BuiltinDatabase

type BuiltinDatabase interface {
	Names() (container, database string, ok bool)
	Ensure(ctx context.Context) (url string, err error)
}

BuiltinDatabase is AppTown's built-in database, which the composition root makes, names and dumps (dbboot.go), and which a restore always loads into: Names is what db.env says its container and database are (false: there is none), Ensure starts or makes it and answers its URL once it answers.

type ControlReply

type ControlReply struct {
	Say    string  `json:"say,omitempty"`
	Report *Report `json:"report,omitempty"`
	Error  string  `json:"error,omitempty"`
}

ControlReply is one line of the reply.

type ControlRequest

type ControlRequest struct {
	Op         string `json:"op"` // "backup"
	Archive    string `json:"archive"`
	Passphrase string `json:"passphrase"`
	Store      bool   `json:"store"`
	User       string `json:"user"` // the operating-system user the command runs as, self-reported
}

ControlRequest is what `apptownd backup` asks.

type Database

type Database interface {
	Dump(ctx context.Context, path string) error
	DumpClientVersion(ctx context.Context) (string, error)
}

Database is the database a backup dumps, the built-in one or the -db-url one (the composition root's databaseDump): Dump writes a whole gzipped plain dump at path, without owners or privileges so it loads into the built-in database, or nothing; DumpClientVersion is the pg_dump that does it.

type DatabaseProvenance

type DatabaseProvenance struct {
	Engine            string `json:"engine"`
	ServerVersionNum  int    `json:"serverVersionNum"`
	DumpClientVersion string `json:"dumpClientVersion"`
}

DatabaseProvenance records observed engine and dump-client versions. It is absent in legacy archives; it does not certify cross-major compatibility.

type Dependencies

type Dependencies struct {
	DB      *database.DB
	DataDir string
	// Database is the database AppTown runs on, which a backup dumps.
	Database    Database
	Protection  *dataprotection.Service
	Deployment  *deployment.Service
	Deployments *deployment.Deployments
	Targets     *deployment.Targets
	// BuiltInTarget names AppTown's own Docker host.
	BuiltInTarget string
	Secrets       *secret.Service
	// NewWork is AppTown's hold of new jobs and steps.
	NewWork *Hold
	Now     func() time.Time
}

Dependencies are what a backup and the record of a restore run on.

type Hold

type Hold struct {
	// contains filtered or unexported fields
}

Hold is AppTown holding new work for a moment: while it is held, a job waits before its work starts and the workflow dispatcher waits before it starts a step. Work already running goes on. It lives in memory only, so nothing of it is in a database dump and a stop releases it. A whole-AppTown backup holds it across the database dump and the copy of the data directory (backup.go). The zero value holds nothing.

func (*Hold) Hold

func (h *Hold) Hold() (release func(), ok bool)

Hold holds new work until release is called; false when it is already held (one backup at a time holds it).

func (*Hold) Wait

func (h *Hold) Wait(ctx context.Context) error

Wait returns at once when nothing is held, else once it is released, or with ctx's error when ctx ends first.

type Manifest

type Manifest struct {
	Database *DatabaseProvenance `json:"database,omitempty"`
	Format   string              `json:"format"`
	Version  int                 `json:"version"`
	// Build is the apptownd that took it; Schema its database's version.
	Build   string `json:"build"`
	Schema  int    `json:"schema"`
	AppTown ids.ID `json:"apptown"` // AppTown's own id (forge.id)
	TakenAt string `json:"takenAt"`
	Host    string `json:"host"`
	// DataDir is where the data directory was: a restore elsewhere moves the
	// records of the sets kept in it.
	DataDir  string                          `json:"dataDir"`
	Dump     backuparchive.Digest            `json:"dump"`
	KeyFiles map[string]backuparchive.Digest `json:"keyFiles"`
	// ExternalSecrets says where values AppTown reads but does not hold
	// are kept; "" when there is no such store.
	ExternalSecrets string `json:"externalSecrets,omitempty"`
	// NotIncluded says what the archive does not carry.
	NotIncluded []string `json:"notIncluded"`
	// Left are files of the data directory no archive can carry (sockets).
	Left []string `json:"left,omitempty"`
}

Manifest says what a whole-AppTown archive holds.

func Restore

func Restore(ctx context.Context, in RestoreRequest) (*Manifest, error)

Restore unpacks and loads an archive, and says what it held. Anything it wrote stays when it fails: a fresh host is cleared by hand.

type PendingRestore

type PendingRestore struct {
	Manifest *Manifest
	// contains filtered or unexported fields
}

PendingRestore is a completely loaded archive whose offline relocation and AfterRestore bookkeeping must finish before ordinary startup.

func ReadPendingRestore

func ReadPendingRestore(dataDir string) (*PendingRestore, error)

ReadPendingRestore is read-only and belongs before database/schema effects. An interrupted extraction or load is not a normal installed database.

type Report

type Report struct {
	Archive  string        `json:"archive"`
	Bytes    int64         `json:"bytes"`
	SHA256   string        `json:"sha256"`
	StoreKey string        `json:"storeKey,omitempty"`
	Manifest Manifest      `json:"manifest"`
	Held     time.Duration `json:"held"` // how long new work was held
	Problems []string      `json:"problems,omitempty"`
}

Report is what a backup did.

func AskControl

func AskControl(ctx context.Context, dataDir string, req ControlRequest, say func(string)) (*Report, error)

AskControl sends one request to the AppTown whose data directory is dataDir and calls say for each step; it returns the report, or the error AppTown answered, or that AppTown could not be reached.

type Request

type Request struct {
	Archive    string
	Passphrase string
	ToStore    bool
	// Actor is who asked, as the host's administrator names themselves.
	Actor string
	// Say is told each step as it starts; nil says nothing.
	Say func(string)
}

Request is what a backup is asked to do: write the archive at an absolute path outside the data directory, encrypted with Passphrase, and copy it to the backup store when ToStore.

type RestoreRequest

type RestoreRequest struct {
	DataDir string
	// LayoutVersion is the daemon's data layout, the only one it restores,
	// checked before DB effects.
	LayoutVersion int
	Archive       string
	Passphrase    string
	Say           func(string) // each step as it starts; nil says nothing
	Docker        docker.Scope
	Database      BuiltinDatabase
}

RestoreRequest is a restore of an archive into an empty data directory, on Docker (the host's own), making the built-in database Database names once the archive's db.env is in place.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service takes whole-AppTown backups and records what a restored AppTown does when it first starts.

func New

func New(deps Dependencies) *Service

New builds the service.

func (*Service) AfterRestore

func (s *Service) AfterRestore(ctx context.Context, m *Manifest) (AfterRestoreReport, error)

AfterRestore records, in the restored database, what the restored AppTown must do when it first starts: the sets kept on disk found where the data directory now is, App Platform and Portainer deployments held until their providers are read, and each built-in deployment held until its rebuild puts its data back; and the receipt.

func (*Service) Backup

func (s *Service) Backup(ctx context.Context, in Request) (Report, error)

Backup takes a whole-AppTown backup. An error is a backup that was not written; a problem after it was written (the copy to the store, the receipt) is in the report's problems.

func (*Service) ServeControl

func (s *Service) ServeControl(ctx context.Context) error

ServeControl serves the control socket until ctx ends. A socket that cannot be made is logged and AppTown runs on without it: `apptownd backup` then says it cannot reach AppTown.

Jump to

Keyboard shortcuts

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