mailbackup

package
v0.9.0 Latest Latest
Warning

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

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

Documentation

Overview

Package mailbackup is the pure core of mail service backup and restore: mox backup and verifydata via a Runner, a streamed tar, zstd, age archive into a Sink, a manifest, and a guarded restore. It has no API or DB code.

Index

Constants

View Source
const DefaultLocalCapMB = 2048

DefaultLocalCapMB applies only when APP_MAIL_BACKUP_LOCAL_CAP_MB is unset.

View Source
const DefaultMinKeep = 3

DefaultMinKeep applies only when APP_MAIL_BACKUP_MIN_KEEP is unset.

Variables

This section is empty.

Functions

func CapFromEnv

func CapFromEnv(getenv func(string) string) (int64, error)

CapFromEnv reads the local folder cap in bytes from the environment.

func ManifestName

func ManifestName(id string) string

ManifestName is the sink name of a backup's manifest.

func MinKeepFromEnv

func MinKeepFromEnv(getenv func(string) string) (int, error)

MinKeepFromEnv reads how many newest verified backups pruning always keeps.

Types

type BackupSpec

type BackupSpec struct {
	Runner Runner
	Sink   Sink
	// StagingHost and StagingContainer are the same directory seen from
	// the host and from inside the mail container.
	StagingHost      string
	StagingContainer string
	Recipients       []age.Recipient
	Now              func() time.Time
	// Fetch copies the container staging dir to the host one when they are
	// not the same directory (a Docker volume the control plane cannot see).
	Fetch func(ctx context.Context, containerDir, hostDir string) error
	// FetchConfig copies the mox config dir (DKIM keys, certificates) into
	// hostDir; nil leaves the config out of the archive.
	FetchConfig func(ctx context.Context, hostDir string) error
	// Cleanup removes the container staging dir; nil means host removal covers it.
	Cleanup func(ctx context.Context, containerDir string)
	// Progress reports each step by name.
	Progress func(step string)
}

BackupSpec configures one backup run.

type CapError

type CapError struct {
	CapBytes  int64
	NeedBytes int64
}

CapError means a backup cannot fit the local folder cap even alone.

func (*CapError) Error

func (e *CapError) Error() string

type ChecksumError

type ChecksumError struct{ Want, Got string }

ChecksumError means the stored archive does not match its manifest.

func (*ChecksumError) Error

func (e *ChecksumError) Error() string

type DowngradeError

type DowngradeError struct{ Target, Backup string }

DowngradeError means the target mox is older than the backup's mox.

func (*DowngradeError) Error

func (e *DowngradeError) Error() string

type LocalSink

type LocalSink struct {
	Dir      string
	CapBytes int64
	MinKeep  int
}

LocalSink stores backups in one folder under a size cap. MinKeep newest verified backups survive pruning even when that leaves the folder over the cap.

func (*LocalSink) Delete

func (s *LocalSink) Delete(_ context.Context, name string) error

Delete implements Sink.

func (*LocalSink) List

func (s *LocalSink) List(_ context.Context) ([]string, error)

List implements Sink.

func (*LocalSink) Open

func (s *LocalSink) Open(_ context.Context, name string) (io.ReadCloser, error)

Open implements Sink.

func (*LocalSink) Prune

func (s *LocalSink) Prune(ctx context.Context) ([]string, error)

Prune removes oldest backups until the folder fits the cap. The newest MinKeep (at least one) verified backups are never removed; when they alone exceed the cap, a CapError is returned instead.

func (*LocalSink) Put

func (s *LocalSink) Put(_ context.Context, name string, r io.Reader) error

Put streams r to a temp file and renames it, so readers never see a partial backup and a cap failure leaves existing backups untouched.

func (*LocalSink) UsedBytes

func (s *LocalSink) UsedBytes() (int64, error)

UsedBytes sums the size of every object in a local sink.

type Manifest

type Manifest struct {
	ID          string    `json:"id"`
	MoxVersion  string    `json:"mox_version"`
	CreatedAt   time.Time `json:"created_at"`
	Files       int       `json:"files"`
	Bytes       int64     `json:"bytes"`
	SHA256      string    `json:"sha256"`
	ArchiveName string    `json:"archive_name"`
	Verified    bool      `json:"verified"`
}

Manifest describes one backup. It is stored next to the archive, because it carries the archive checksum and so cannot live inside it.

func Backup

func Backup(ctx context.Context, spec BackupSpec) (Manifest, error)

Backup runs mox backup into a staging dir, verifies it, then streams the archive and manifest to the sink. Staging is removed on every path.

func Check

func Check(ctx context.Context, spec RestoreSpec) (Manifest, error)

Check reads the manifest and applies the downgrade guard without reading the archive.

func List

func List(ctx context.Context, sink Sink) ([]Manifest, error)

List reads every manifest in the sink, newest first. Unreadable manifests are skipped so one damaged file does not hide the rest.

type Pruner

type Pruner interface {
	Prune(ctx context.Context) ([]string, error)
}

Pruner is implemented by sinks that enforce a size cap after a backup.

type RestoreReport

type RestoreReport struct {
	Manifest Manifest
	Files    int
	Bytes    int64
	DryRun   bool
}

RestoreReport says what a restore did, or with dryRun would do.

func Restore

func Restore(ctx context.Context, spec RestoreSpec, dryRun bool) (RestoreReport, error)

Restore checks the downgrade guard, then in one pass over the archive verifies its checksum and either counts (dryRun) or extracts into DestDir.

type RestoreSpec

type RestoreSpec struct {
	Runner     Runner
	Sink       Sink
	ID         string
	DestDir    string
	Identities []age.Identity
}

RestoreSpec configures one restore run.

type Runner

type Runner interface {
	Run(ctx context.Context, args ...string) (string, error)
}

Runner executes `mox <args>` inside the mail container and returns stdout. It is an interface so tests never need a container.

type Sink

type Sink interface {
	Put(ctx context.Context, name string, r io.Reader) error
	Open(ctx context.Context, name string) (io.ReadCloser, error)
	List(ctx context.Context) ([]string, error)
	Delete(ctx context.Context, name string) error
}

Sink stores named blobs. Put must stream r without buffering it whole.

Directories

Path Synopsis
Package moxrun runs mailbackup steps against a mox container over the Docker API: exec for mox commands, tar copy for staging, and a short-lived helper container for the data swap while mox is stopped.
Package moxrun runs mailbackup steps against a mox container over the Docker API: exec for mox commands, tar copy for staging, and a short-lived helper container for the data swap while mox is stopped.

Jump to

Keyboard shortcuts

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