backup

package
v0.10.1 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 48 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ConfidenceExact     = "exact"
	ConfidenceStrong    = "strong"
	ConfidenceAmbiguous = "ambiguous"
	ConfidenceUnknown   = "unknown"
	ConfidenceLocked    = "locked"
)
View Source
const (
	DefaultFilenameTemplate = "{connection}_{engine}_{date}_{time}_{run}"
	DefaultTimeoutMinutes   = 30
)
View Source
const (
	RestoreModeMerge RestoreMode = "merge"
	RestoreModeClean RestoreMode = "clean"

	// Short aliases keep call sites readable while retaining the enum-style
	// names used by the other backup model types.
	RestoreMerge = RestoreModeMerge
	RestoreClean = RestoreModeClean
)
View Source
const (
	// DefaultMaxDecodedBytes limits each decoded wrapper layer. Inspection
	// materializes decoded layers on disk rather than retaining database dumps
	// in memory.
	DefaultMaxDecodedBytes int64 = 1 << 30 // 1 GiB

)
View Source
const RcloneDestinationPrefix = "rclone://"

Variables

View Source
var ErrJobBusy = errors.New("backup job is already running")

Functions

func AgentProcessRunning

func AgentProcessRunning() (bool, error)

AgentProcessRunning reports whether the default backup catalog's scheduler lock is currently held. The lock file itself is persistent; only the kernel lock is authoritative, so a crash cannot strand the agent in a running state.

func ApplyRetention

func ApplyRetention(ctx context.Context, store *Store, job Job, now time.Time) ([]string, error)

ApplyRetention removes only successful artifacts recorded for this job and still contained by its configured destination. The newest success is always retained, even when an age policy would otherwise remove it.

func CreateNativeBackup

func CreateNativeBackup(ctx context.Context, cfg *config.ConnectionConfig, outputPath string, options NativeOptions) (err error)

CreateNativeBackup writes the engine-native format and refuses to replace an existing destination. It is shared by the instant-backup UI and scheduler.

func DefaultStagingPath

func DefaultStagingPath() (string, error)

DefaultStagingPath returns the private state path used for raw native dumps. It does not create the staging directory or a backup artifact.

func DefaultStorePath

func DefaultStorePath() (string, error)

func ExecuteRestore

func ExecuteRestore(ctx context.Context, plan *RestorePlan, emit func(string)) error

func FormatByteSize

func FormatByteSize(size uint64) string

func GenerateAgeIdentity

func GenerateAgeIdentity(path string) (string, error)

GenerateAgeIdentity creates a private age X25519 identity with no-clobber semantics. Jobs store only the returned public recipient.

func IsRemoteBackupDestination added in v0.6.2

func IsRemoteBackupDestination(value string) bool

IsRemoteBackupDestination reports whether value uses dbterm's first-class rclone destination syntax. Invalid rclone values still return true so callers never accidentally reinterpret them as local filesystem paths.

func JoinBackupDestination added in v0.6.2

func JoinBackupDestination(raw, filename string) (string, error)

JoinBackupDestination appends one generated artifact name to either kind of destination without converting a remote URI into a local path.

func NewID

func NewID(prefix string) (string, error)

func NormalizeBackupDestination added in v0.6.2

func NormalizeBackupDestination(raw string) (string, error)

NormalizeBackupDestination validates a local folder or an rclone remote and returns the stable value suitable for a durable backup job.

func RunAgent

func RunAgent(ctx context.Context, store *Store, pollInterval time.Duration, emit func(string)) error

RunAgent executes scheduled jobs sequentially and relies on the durable store lease to prevent overlap with manual invocations or a second agent.

func RunDue

func RunDue(ctx context.Context, store *Store, owner string, now time.Time, emit func(string)) error

func SendRunNotification

func SendRunNotification(ctx context.Context, job Job, run Run) (err error)

SendRunNotification sends a terminal run result according to the job policy. It never includes SMTP credentials in the message and redacts them from all returned errors, including errors returned by the remote SMTP server.

func TestEmailNotification

func TestEmailNotification(ctx context.Context, notification EmailNotification) (err error)

TestEmailNotification validates and exercises the same SMTP/TLS/auth path as scheduled notifications, regardless of the saved delivery policy. It lets a client verify credentials and routing before depending on a future backup.

Types

type AgentActivity

type AgentActivity struct {
	JobID        string    `json:"job_id"`
	JobName      string    `json:"job_name"`
	RunID        string    `json:"run_id"`
	Phase        string    `json:"phase"`
	Message      string    `json:"message"`
	CurrentBytes int64     `json:"current_bytes,omitempty"`
	TotalBytes   int64     `json:"total_bytes,omitempty"`
	StartedAt    time.Time `json:"started_at"`
	UpdatedAt    time.Time `json:"updated_at"`
}

type AgentStatus

type AgentStatus struct {
	Heartbeat time.Time      `json:"heartbeat"`
	PID       int            `json:"pid"`
	Healthy   bool           `json:"healthy"`
	Activity  *AgentActivity `json:"activity,omitempty"`
}

func AgentHealth

func AgentHealth(ctx context.Context, store *Store, now time.Time) (AgentStatus, error)

type Artifact

type Artifact struct {
	Path        string    `json:"path"`
	Size        int64     `json:"size"`
	SHA256      string    `json:"sha256"`
	Format      string    `json:"format"`
	Verified    bool      `json:"verified"`
	CreatedAt   time.Time `json:"created_at"`
	BackupName  string    `json:"backup_name,omitempty"`
	PrunedAt    time.Time `json:"pruned_at,omitempty"`
	PruneReason string    `json:"prune_reason,omitempty"`
}

type Compression

type Compression string
const (
	CompressionNone Compression = "none"
	CompressionGzip Compression = "gzip"
	CompressionZip  Compression = "zip"
	CompressionZstd Compression = "zstd"
)

type DiskUsage

type DiskUsage struct {
	Path           string
	Volume         string
	CapacityBytes  uint64
	FreeBytes      uint64
	AvailableBytes uint64
}

func DestinationDiskUsage

func DestinationDiskUsage(path string) (DiskUsage, error)

DestinationDiskUsage reports capacity for the filesystem that will contain path. The destination itself need not exist yet; its nearest existing parent is used for the operating-system query.

type EmailNotification

type EmailNotification struct {
	Policy     NotificationPolicy `json:"policy"`
	SMTPHost   string             `json:"smtp_host,omitempty"`
	SMTPPort   int                `json:"smtp_port,omitempty"`
	TLSMode    SMTPTLSMode        `json:"tls_mode,omitempty"`
	Recipients []string           `json:"recipients,omitempty"`
	Username   string             `json:"username,omitempty"`
	Password   string             `json:"password,omitempty"`
	From       string             `json:"from,omitempty"`
}

EmailNotification is stored in the private backup catalog as part of the job JSON. Password is necessarily plaintext so the unattended OS service can authenticate; the SQLite catalog and its parent state directory are protected with 0600/0700 permissions and must be treated as secrets.

func (EmailNotification) ShouldNotify

func (notification EmailNotification) ShouldNotify(status RunStatus) bool

func (EmailNotification) Validate

func (notification EmailNotification) Validate() error

type Encryption

type Encryption string
const (
	EncryptionNone Encryption = "none"
	EncryptionAge  Encryption = "age"
)

type Format

type Format string
const (
	FormatPostgresCustom Format = "postgres_custom"
	FormatPostgresTar    Format = "postgres_tar"
	FormatPostgresSQL    Format = "postgres_sql"
	FormatMySQLSQL       Format = "mysql_sql"
	FormatSQLiteDatabase Format = "sqlite_database"
	FormatSQLiteSQL      Format = "sqlite_sql"
	FormatGenericSQL     Format = "generic_sql"
	FormatUnknown        Format = "unknown"
)

type InspectOptions

type InspectOptions struct {
	AgeIdentityPath string
	MaxDecodedBytes int64
}

type Inspection

type Inspection struct {
	Path          string
	Size          int64
	SHA256        string
	Wrappers      []Wrapper
	Format        Format
	Engine        config.DBType
	Confidence    string
	Evidence      []string
	Warnings      []string
	Locked        bool
	RequiredTools []string
}

func Inspect

func Inspect(ctx context.Context, path string, opts InspectOptions) (*Inspection, error)

Inspect identifies a database backup from its bytes, independently of its filename. The SHA-256 digest and Size always describe the original outer artifact, while Wrappers is ordered outermost first.

type Job

type Job struct {
	ID               string            `json:"id"`
	Name             string            `json:"name"`
	ConnectionID     string            `json:"connection_id"`
	Enabled          bool              `json:"enabled"`
	Destination      string            `json:"destination"`
	FilenameTemplate string            `json:"filename_template"`
	Compression      Compression       `json:"compression"`
	CompressionLevel int               `json:"compression_level"`
	Encryption       Encryption        `json:"encryption"`
	AgeRecipient     string            `json:"age_recipient,omitempty"`
	Schedule         Schedule          `json:"schedule"`
	Retention        Retention         `json:"retention"`
	Notification     EmailNotification `json:"notification,omitempty"`
	TimeoutMinutes   int               `json:"timeout_minutes"`
	CreatedAt        time.Time         `json:"created_at"`
	UpdatedAt        time.Time         `json:"updated_at"`
	LastRunAt        time.Time         `json:"last_run_at,omitempty"`
	NextRunAt        time.Time         `json:"next_run_at,omitempty"`
}

Job is a durable backup policy. It references a saved connection by its stable ID so renaming or reordering dashboard entries cannot redirect it.

func (*Job) ApplyDefaults

func (j *Job) ApplyDefaults(now time.Time) error

func (Job) Validate

func (j Job) Validate() error

type NativeOptions

type NativeOptions struct {
	PostgresCompression int
	Progress            ProgressFunc
	// contains filtered or unexported fields
}

type NativePlan

type NativePlan struct {
	Format      string
	FormatLabel string
	ToolLabel   string
	Extension   string
}

func PlanFor

func PlanFor(cfg *config.ConnectionConfig) (NativePlan, error)

type NotificationPolicy

type NotificationPolicy string
const (
	NotificationNever   NotificationPolicy = "never"
	NotificationFailure NotificationPolicy = "failure"
	NotificationSuccess NotificationPolicy = "success"
	NotificationBoth    NotificationPolicy = "both"
)

type ProgressEvent

type ProgressEvent struct {
	Phase        string
	Message      string
	CurrentBytes int64
	TotalBytes   int64
	Elapsed      time.Duration
}

ProgressEvent describes a bounded, low-overhead backup status update. A zero TotalBytes means that the native database tool cannot report its final size in advance; CurrentBytes still reflects the staging file observed on disk.

type ProgressFunc

type ProgressFunc func(ProgressEvent)

type RestoreMode

type RestoreMode string

type RestoreOptions

type RestoreOptions struct {
	Mode              RestoreMode
	StopOnError       bool
	SingleTransaction bool
	AgeIdentityPath   string
	// MaxDecodedBytes limits each decoded wrapper layer. Zero uses
	// DefaultMaxDecodedBytes.
	MaxDecodedBytes int64
}

type RestorePlan

type RestorePlan struct {
	Inspection *Inspection
	Target     config.ConnectionConfig
	Options    RestoreOptions
	Warnings   []string
}

func BuildRestorePlan

func BuildRestorePlan(inspection *Inspection, target *config.ConnectionConfig, options RestoreOptions) (*RestorePlan, error)

BuildRestorePlan performs every check that does not require opening the artifact or connecting to the target. ExecuteRestore repeats this validation so a caller cannot bypass it by mutating or hand-building a plan.

type Retention

type Retention struct {
	KeepLast      int   `json:"keep_last"`
	MaxAgeDays    int   `json:"max_age_days"`
	MaxTotalBytes int64 `json:"max_total_bytes,omitempty"`
}

type Run

type Run struct {
	ID                    string    `json:"id"`
	JobID                 string    `json:"job_id"`
	Trigger               Trigger   `json:"trigger"`
	Status                RunStatus `json:"status"`
	StartedAt             time.Time `json:"started_at"`
	FinishedAt            time.Time `json:"finished_at,omitempty"`
	Artifact              Artifact  `json:"artifact,omitempty"`
	Error                 string    `json:"error,omitempty"`
	NotificationAttempted bool      `json:"notification_attempted,omitempty"`
	NotificationSent      bool      `json:"notification_sent,omitempty"`
	NotificationError     string    `json:"notification_error,omitempty"`
}

func RunJobNow

func RunJobNow(ctx context.Context, store *Store, idOrName string, emit func(string)) (Run, error)

func RunJobNowWithProgress

func RunJobNowWithProgress(ctx context.Context, store *Store, idOrName string, progress ProgressFunc) (Run, error)

RunJobNowWithProgress runs a claimed job and reports structured progress for clients that want byte counts and elapsed time instead of formatted lines.

type RunStatus

type RunStatus string
const (
	RunRunning   RunStatus = "running"
	RunSucceeded RunStatus = "succeeded"
	RunFailed    RunStatus = "failed"
	RunCanceled  RunStatus = "canceled"
)

type Runner

type Runner struct {
	Now      func() time.Time
	Progress ProgressFunc
}

func (Runner) Run

func (r Runner) Run(ctx context.Context, job Job, cfg *config.ConnectionConfig, runID string) (artifact Artifact, err error)

type SMTPTLSMode

type SMTPTLSMode string
const (
	SMTPTLSStartTLS SMTPTLSMode = "starttls"
	SMTPTLSImplicit SMTPTLSMode = "implicit"
	SMTPTLSNone     SMTPTLSMode = "none"
)

type Schedule

type Schedule struct {
	Kind            ScheduleKind `json:"kind"`
	EveryMinutes    int          `json:"every_minutes,omitempty"`
	TimeOfDay       string       `json:"time_of_day,omitempty"`
	Weekdays        []int        `json:"weekdays,omitempty"`
	Timezone        string       `json:"timezone,omitempty"`
	RunMissedOnWake bool         `json:"run_missed_on_wake"`
}

func (Schedule) AdvancePast

func (s Schedule) AdvancePast(scheduled, now time.Time) (time.Time, bool, error)

AdvancePast returns the first scheduled occurrence strictly after now while preserving the original cadence for interval schedules. It is used when a sleeping agent intentionally skips an overdue run.

func (Schedule) Next

func (s Schedule) Next(after time.Time) (time.Time, bool, error)

func (Schedule) Validate

func (s Schedule) Validate() error

type ScheduleKind

type ScheduleKind string
const (
	ScheduleManual   ScheduleKind = "manual"
	ScheduleInterval ScheduleKind = "interval"
	ScheduleDaily    ScheduleKind = "daily"
	ScheduleWeekly   ScheduleKind = "weekly"
)

type Store

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

func OpenDefaultStore

func OpenDefaultStore() (*Store, error)

func OpenStore

func OpenStore(path string) (*Store, error)

func (*Store) ClaimDueJobs

func (s *Store) ClaimDueJobs(ctx context.Context, now time.Time, owner string, limit int) ([]Job, error)

func (*Store) ClaimJob

func (s *Store) ClaimJob(ctx context.Context, idOrName, owner string, now time.Time) (Job, error)

func (*Store) Close

func (s *Store) Close() error

func (*Store) DeleteJob

func (s *Store) DeleteJob(ctx context.Context, id string) error

func (*Store) FinishRun

func (s *Store) FinishRun(ctx context.Context, run *Run, leaseOwner string) error

func (*Store) GetJob

func (s *Store) GetJob(ctx context.Context, idOrName string) (Job, error)

func (*Store) GetMeta

func (s *Store) GetMeta(ctx context.Context, key string) (string, bool, error)

func (*Store) LatestRun

func (s *Store) LatestRun(ctx context.Context, jobID string) (Run, bool, error)

func (*Store) ListJobs

func (s *Store) ListJobs(ctx context.Context) ([]Job, error)

func (*Store) ListRuns

func (s *Store) ListRuns(ctx context.Context, jobID string, limit int) ([]Run, error)

func (*Store) MarkArtifactPruned

func (s *Store) MarkArtifactPruned(ctx context.Context, runID, reason string, at time.Time) error

func (*Store) ReconcileStaleRuns

func (s *Store) ReconcileStaleRuns(ctx context.Context, now time.Time) (int, error)

ReconcileStaleRuns closes history entries abandoned by a crashed process. A running entry is stale only when its job no longer has an unexpired lease; the conditional update repeats that check inside the transaction so an actively leased run is never rewritten.

func (*Store) ReleaseJob

func (s *Store) ReleaseJob(ctx context.Context, jobID, leaseOwner string) error

func (*Store) SetJobEnabled

func (s *Store) SetJobEnabled(ctx context.Context, id string, enabled bool) error

func (*Store) SetMeta

func (s *Store) SetMeta(ctx context.Context, key, value string) error

func (*Store) StartRun

func (s *Store) StartRun(ctx context.Context, jobID string, trigger Trigger, now time.Time) (Run, error)

func (*Store) UpsertJob

func (s *Store) UpsertJob(ctx context.Context, job *Job) error

type Trigger

type Trigger string
const (
	TriggerManual    Trigger = "manual"
	TriggerScheduled Trigger = "scheduled"
)

type Wrapper

type Wrapper string
const (
	WrapperGzip Wrapper = "gzip"
	WrapperZstd Wrapper = "zstd"
	WrapperZip  Wrapper = "zip"
	WrapperAge  Wrapper = "age"
)

Jump to

Keyboard shortcuts

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