backup

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: AGPL-3.0 Imports: 27 Imported by: 0

Documentation

Overview

Package backup keeps backups as files on this server. Every backup is compressed with zstd and then encrypted with age, locally too, so a copy of a backup file on its own gives nothing away. The key lives with the core; its owner can download it as a recovery file and open any backup with the standard age and zstd tools, without Zelie.

Index

Constants

View Source
const KindVolumes = "volumes"

KindVolumes is the backup of an app's volumes, as one tar archive.

Variables

View Source
var (

	// ErrImportPgCustom is exported for the panel, which says it as soon as
	// a file is named like one.
	ErrImportPgCustom = msg.Define(http.StatusUnprocessableEntity, "import.pg_custom", "This dump is in pg_dump's custom format. Upload a plain SQL dump (pg_dump -Fp), or turn this one into SQL with pg_restore -f dump.sql.")
)
View Source
var ErrInvalid = errors.New("invalid name")

ErrInvalid is returned for an app or backup name that is not allowed.

View Source
var ErrNoKey = errors.New("no backup key found")

ErrNoKey is returned for a recovery file with no key in it.

Functions

func Dump

func Dump(ctx context.Context, exec Exec, k string, w io.Writer) error

Dump writes a database's dump to w.

func Ext

func Ext(k string) (string, bool)

Ext is the extension of the files a kind makes.

func Kinds

func Kinds() []string

Kinds lists the kinds of backup a database can have.

func Load

func Load(ctx context.Context, exec Exec, k string, dump io.Reader) error

Load replaces a running database with a dump. The dump is copied into the container and checked before the database is touched.

func LoadsInPlace

func LoadsInPlace(k string) bool

LoadsInPlace reports whether a kind restores into the running database. Redis does not: its files are replaced while it is stopped.

func RestoreRedis

func RestoreRedis(vol *os.Root, rdb io.Reader) error

RestoreRedis puts an RDB file in place in a stopped Redis's volume. With append-only files on, Redis ignores a plain dump.rdb and starts empty; the dump has to become the base of a new append-only directory.

func RestoreTar

func RestoreTar(ctx context.Context, r io.Reader, vols []Volume) ([]string, error)

RestoreTar replaces the volumes' files with what the archive holds. Everything is unpacked next to the current files first; only when the whole archive is in are the old files swapped out, so a broken archive changes nothing. Folders in the archive with no volume are skipped, and a volume with no folder in the archive is left as it is. It returns the folders that were restored.

The archive is not trusted. Every path stays inside its volume, and nothing is written through a symbolic link the archive itself made.

func ValidApp

func ValidApp(app string) bool

ValidApp reports whether app can name a folder of backups.

func ValidName

func ValidName(name string) bool

ValidName reports whether name is a backup file's name. Names come from the panel and end up in paths, so nothing else is let through.

Types

type Adapted

type Adapted map[string]int

Adapted counts the statements an import took out or changed, by what they were.

func ImportDump

func ImportDump(k string, r io.Reader, w io.Writer) (Adapted, error)

ImportDump reads an uploaded dump for a database of kind k, compressed or not, and writes what the database can load to w.

type Dir

type Dir struct {
	Root string
	Key  *Key
	// contains filtered or unexported fields
}

Dir holds the backups, one directory per app.

func (*Dir) Create

func (d *Dir) Create(app, ext string) (*Writer, error)

Create starts a backup of app. ext says what is inside: sql, rdb, tar.

func (*Dir) Import

func (d *Dir) Import(app, name string, r io.Reader) error

Import saves a backup file made elsewhere, as it is: still encrypted, and checked only when it is opened. A backup already here is kept.

func (*Dir) List

func (d *Dir) List(app string) ([]Info, error)

List returns the backups of app, newest first.

func (*Dir) Open

func (d *Dir) Open(app, name string) (io.ReadCloser, error)

Open reads a backup back as it was before it was compressed.

func (*Dir) OpenRaw

func (d *Dir) OpenRaw(app, name string) (*os.File, error)

OpenRaw opens the encrypted file, for downloads.

func (*Dir) Remove

func (d *Dir) Remove(app, name string) error

Remove deletes one backup.

type Exec

type Exec func(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) (uint32, error)

Exec runs a command in the database's container, as root there and with the container's environment, which holds the database's password.

type Info

type Info struct {
	Name    string    `json:"name"`
	Bytes   int64     `json:"bytes"`
	Created time.Time `json:"created"`
	// For volume backups: the size of the files inside, and how many
	// changed while they were copied.
	Size    int64 `json:"size,omitempty"`
	Changed int   `json:"changed,omitempty"`
	// For a dump someone uploaded: what was changed so it loads here.
	Adapted Adapted `json:"adapted,omitempty"`
}

Info describes a backup file.

type Key

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

Key encrypts and opens backups. Keys added from other recovery files, kept next to it with .old added to its name, only open them: backups brought over from another server, or made before the key changed.

func LoadOrCreateKey

func LoadOrCreateKey(path string) (*Key, error)

LoadOrCreateKey reads the key at path, creating it the first time.

func (*Key) AddOld

func (k *Key) AddOld(recovery string) ([]string, error)

AddOld keeps the keys of another recovery file, to open what they encrypted. It returns the public halves of the keys that were new.

func (*Key) Opens

func (k *Key) Opens(public string) bool

Opens reports whether this key, or one added to it, opens what was encrypted for public.

func (*Key) Public

func (k *Key) Public() string

Public is the key's public half. It encrypts, but opens nothing.

func (*Key) Recovery

func (k *Key) Recovery(host string, now time.Time) string

Recovery is the key as a file its owner keeps off the server. The age tool reads it as an identity file; the lines starting with # are for the person who finds it later.

func (*Key) Seal

func (k *Key) Seal(b []byte) ([]byte, error)

Seal encrypts a small piece of data, such as what a backup holds.

func (*Key) Unseal

func (k *Key) Unseal(b []byte, max int64) ([]byte, error)

Unseal opens what Seal made, up to max bytes of it.

type TarStats

type TarStats struct {
	Files int
	// Bytes is the size of the files, which a restore needs on disk.
	Bytes int64
	// Changed counts files that changed while they were copied, which
	// only happens when the app keeps running during its backup.
	Changed int
}

TarStats says what went into an archive.

func WriteTar

func WriteTar(ctx context.Context, w io.Writer, vols []Volume) (TarStats, error)

WriteTar writes the volumes into one tar archive. File owners are kept as numbers: they are the container's users, which mean nothing on the host. Sockets, pipes and devices are left out, and so are extended attributes.

type Volume

type Volume struct {
	Dir  string
	Root *os.Root
}

Volume is one of an app's volumes in a backup. Dir is the folder it gets in the archive: where the app sees it, without the leading slash, so an archive opened by hand reads like the app's own file tree.

type Writer

type Writer struct {
	io.Writer
	// contains filtered or unexported fields
}

Writer is a backup being written. Nothing appears under its name until Commit; Abort, or a crash, leaves only a temporary file behind.

func (*Writer) Abort

func (w *Writer) Abort()

Abort throws the file away.

func (*Writer) Commit

func (w *Writer) Commit() (Info, error)

Commit finishes the file and gives it its name.

Jump to

Keyboard shortcuts

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