cpbackup

package
v0.8.1 Latest Latest
Warning

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

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

Documentation

Overview

Package cpbackup manages control plane self-backups: verified SQLite snapshots kept in a directory under the data dir.

Index

Constants

View Source
const (
	EnvReplicaInterval = "APP_CONTROL_PLANE_REPLICA_INTERVAL"
	ReplicaPrefix      = "cp-replica"
)

Continuous replica: an opt-in, off-by-default loop that re-ships an encrypted snapshot of the control plane database whenever it changed, to the same destination the scheduled backups use.

View Source
const (
	EnvOffboxSchedule    = "APP_CONTROL_PLANE_OFFBOX_SCHEDULE"
	EnvRetainDaily       = "APP_CONTROL_PLANE_OFFBOX_RETAIN_DAILY"
	EnvRetainWeekly      = "APP_CONTROL_PLANE_OFFBOX_RETAIN_WEEKLY"
	EnvRetainMonthly     = "APP_CONTROL_PLANE_OFFBOX_RETAIN_MONTHLY"
	EnvMaxPrune          = "APP_CONTROL_PLANE_OFFBOX_MAX_PRUNE_PER_RUN"
	EnvTick              = "APP_CONTROL_PLANE_OFFBOX_TICK"
	EnvRetryAfter        = "APP_CONTROL_PLANE_OFFBOX_RETRY_AFTER"
	EnvDrillSchedule     = "APP_CONTROL_PLANE_DRILL_SCHEDULE"
	EnvDrillIdentityFile = "APP_CONTROL_PLANE_DRILL_IDENTITY_FILE"
	EnvGrace             = "APP_CONTROL_PLANE_DR_GRACE"
)

Env vars tuning off-box backups; unset or invalid values use the defaults.

View Source
const DirName = "control-plane-backups"

DirName is the backup directory's name under the data dir.

View Source
const EscrowPrefix = "cp-escrow"

EscrowPrefix is the key prefix for escrow bundles uploaded on explicit request.

View Source
const Prefix = "cp-backups"

Prefix is the top-level key prefix for off-box control plane backups.

Variables

View Source
var (
	// ErrInvalidName means the name does not match the backup file pattern.
	ErrInvalidName = errors.New("invalid backup name")
	// ErrNotFound means no backup with that name exists.
	ErrNotFound = errors.New("backup not found")
)
View Source
var (
	ErrChecksumMismatch = errors.New("downloaded backup does not match its manifest checksum")
	ErrNewerSchema      = errors.New("backup schema is newer than this binary supports")
	ErrInstallMismatch  = errors.New("backup belongs to a different install")
)

Errors a restore can end with.

View Source
var (
	ErrBusy          = errors.New("a run is already in progress")
	ErrNotConfigured = errors.New("off-box backups are not configured: choose a destination and at least one recipient")
	ErrNoBackups     = errors.New("no complete backup exists at the destination yet")
)

Errors callers map to responses.

View Source
var ErrBadManifest = errors.New("invalid backup manifest")

ErrBadManifest means a manifest is unreadable or self-inconsistent.

View Source
var ErrEscrowSameBucket = errors.New("the escrow destination is the same bucket as the backup destination, which defeats the point of escrow: choose a separate destination")

ErrEscrowSameBucket means the escrow upload would land beside the backups it protects.

View Source
var ErrInvalid = errors.New("invalid configuration")

ErrInvalid marks a configuration the operator must fix.

View Source
var ErrNoRecipients = errors.New("at least one age recipient (public key) is required")

ErrNoRecipients means an encryption was asked for without any recipient.

View Source
var ErrNoReplica = errors.New("no replica exists at the destination yet")

ErrNoReplica means no verified replica slot exists at the destination.

View Source
var ErrWrongIdentity = errors.New("none of the supplied identities can decrypt this backup")

ErrWrongIdentity means no supplied identity can decrypt the file.

Functions

func DataKey

func DataKey(installID string, ts time.Time) string

DataKey is the ciphertext object key for a backup taken at ts.

func LatestKey

func LatestKey(ctx context.Context, b Bucket, prefix string) (string, error)

LatestKey returns the newest complete backup under prefix.

func ManifestKey

func ManifestKey(dataKey string) string

ManifestKey is the manifest object key beside a ciphertext key.

func ParseIdentityFile

func ParseIdentityFile(path string) ([]age.Identity, error)

ParseIdentityFile parses an age identity file (one key per line, comments allowed).

func ParseKey

func ParseKey(key string) (installID string, ts time.Time, err error)

ParseKey extracts the install id and timestamp from a ciphertext key.

func ParseRecipients

func ParseRecipients(keys []string) ([]age.Recipient, error)

ParseRecipients parses age public keys, X25519 (age1...) or hybrid (age1pq1...).

func RecipientOf

func RecipientOf(id age.Identity) (string, bool)

RecipientOf derives the public recipient string from a parsed identity, when it has one.

func ReplicaInterval

func ReplicaInterval(lookup func(string) (string, bool)) time.Duration

ReplicaInterval parses EnvReplicaInterval. Zero means off; a value under the minimum is raised to it.

func ReplicaKey

func ReplicaKey(installID, slot string) string

ReplicaKey is the ciphertext key of one of the two alternating slots. Two slots keep a restorable copy in place while the other is overwritten, so an interrupted ship never leaves none.

func ValidName

func ValidName(name string) bool

ValidName reports whether name is a well-formed backup file name.

Types

type AlertSource

type AlertSource struct {
	Local *Manager
	Svc   *Service
	// LocalScheduled is false when scheduled local snapshots are switched off,
	// so their absence is not staleness.
	LocalScheduled bool
}

AlertSource adapts the local snapshot manager and the off-box service to the stale-backup alert rule: when off-box backups are enabled their age counts.

func (AlertSource) DRProblem

func (a AlertSource) DRProblem(now time.Time) string

DRProblem forwards to the service.

func (AlertSource) Newest

func (a AlertSource) Newest() (time.Time, bool, error)

Newest reports the newest off-box backup when enabled, else the newest local snapshot.

type Bucket

type Bucket interface {
	Put(ctx context.Context, key string, body io.ReadSeeker, contentType, contentEncoding string) error
	Get(ctx context.Context, key string) (io.ReadCloser, int64, error)
	Delete(ctx context.Context, key string) error
	List(ctx context.Context, prefix, token string, limit int32) (objectstore.ListPage, error)
}

Bucket is the object store surface off-box backups use; *objectstore.Client satisfies it.

type Check

type Check struct {
	Name   string `json:"name"`
	OK     bool   `json:"ok"`
	Detail string `json:"detail"`
}

Check is one step of a backup verification.

type Checklist

type Checklist struct {
	DestinationChosen  bool `json:"destination_chosen"`
	RecipientSet       bool `json:"recipient_set"`
	EscrowAcknowledged bool `json:"escrow_acknowledged"`
	DrillPassed        bool `json:"drill_passed"`
}

Checklist is the guided setup progress.

type ConfigUpdate

type ConfigUpdate struct {
	Enabled        bool
	TargetID       string
	Recipients     []string
	Schedule       string
	DrillSchedule  string
	Retention      Retention
	EscrowTargetID string
}

ConfigUpdate is the operator-editable configuration.

type Destinations

type Destinations interface {
	Open(ctx context.Context, targetID string) (Bucket, Location, error)
}

Destinations resolves a stored storage destination to a bucket client.

type DrillResult

type DrillResult struct {
	At        time.Time     `json:"at"`
	OK        bool          `json:"ok"`
	Partial   bool          `json:"partial"`
	Detail    string        `json:"detail"`
	BackupKey string        `json:"backup_key,omitempty"`
	Duration  time.Duration `json:"duration_ns"`
	Checks    []Check       `json:"checks"`
}

DrillResult is the outcome of one restore drill.

type DrillStatus

type DrillStatus struct {
	At         *time.Time `json:"at,omitempty"`
	OK         bool       `json:"ok"`
	Partial    bool       `json:"partial"`
	Detail     string     `json:"detail"`
	DurationMs int64      `json:"duration_ms"`
}

DrillStatus is the last drill outcome.

type Effective

type Effective struct {
	Schedule      string    `json:"schedule"`
	DrillSchedule string    `json:"drill_schedule"`
	Retention     Retention `json:"-"`
}

Effective is the configuration in force after applying env defaults.

type Entry

type Entry struct {
	Key       string
	CreatedAt time.Time
}

Entry is one complete backup for retention purposes.

type EscrowBundle

type EscrowBundle struct {
	Armored        string    `json:"armored"`
	Instructions   string    `json:"instructions"`
	Fingerprint    string    `json:"fingerprint"`
	RecipientCount int       `json:"recipient_count"`
	CreatedAt      time.Time `json:"created_at"`
	UploadedKey    string    `json:"uploaded_key,omitempty"`
}

EscrowBundle is a generated escrow file: armored age ciphertext plus a plain-text instruction sheet to store beside it.

type EscrowInput

type EscrowInput struct {
	EscrowMaterial
	Recipients []string
	Upload     bool
}

EscrowInput describes one escrow bundle to build. Recipients, when non-empty, replace the configured ones for this bundle.

type EscrowMaterial

type EscrowMaterial struct {
	MasterKey string
	Files     map[string]string
}

EscrowMaterial is what an escrow bundle protects.

type EscrowPayload

type EscrowPayload struct {
	Version       int       `json:"version"`
	CreatedAt     time.Time `json:"created_at"`
	InstallID     string    `json:"install_id"`
	BinaryVersion string    `json:"binary_version"`
	// MasterKey is the serialized master key identity. Never log it.
	MasterKey       string `json:"master_key"`
	MasterRecipient string `json:"master_recipient"`
	// Files holds other recovery material by file name, such as the agent CA
	// key that lives outside the database. Never log its values.
	Files        map[string]string `json:"files,omitempty"`
	Instructions string            `json:"instructions"`
}

EscrowPayload is what an escrow bundle decrypts to.

func OpenEscrow

func OpenEscrow(bundle []byte, identities []age.Identity) (EscrowPayload, error)

OpenEscrow decrypts an escrow bundle with an identity that matches one of its recipients.

type Identity

type Identity struct {
	// Recipient is the public key, safe to store and share.
	Recipient string
	// Secret is the private key line. Never log it.
	Secret string
}

Identity is a freshly generated age keypair.

func GenerateIdentity

func GenerateIdentity(hybrid bool) (Identity, error)

GenerateIdentity makes an X25519 keypair, or a hybrid post-quantum one when hybrid is set.

type Info

type Info struct {
	Name      string    `json:"name"`
	SizeBytes int64     `json:"size_bytes"`
	CreatedAt time.Time `json:"created_at"`
	SHA256    string    `json:"sha256"`
	// VerifiedAt and VerifiedOK describe the last verification, if any.
	VerifiedAt *time.Time `json:"verified_at,omitempty"`
	VerifiedOK *bool      `json:"verified_ok,omitempty"`
}

Info describes one backup.

type Location

type Location struct {
	TargetID string `json:"target_id"`
	Name     string `json:"name"`
	Endpoint string `json:"endpoint"`
	Bucket   string `json:"bucket"`
}

Location identifies a bucket well enough to tell whether two destinations are the same one.

func (Location) SameBucket

func (l Location) SameBucket(o Location) bool

SameBucket reports whether two locations point at one bucket.

type Manager

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

Manager creates, lists, and prunes backups in one directory.

func NewManager

func NewManager(db Snapshotter, dataDir string) *Manager

NewManager returns a Manager storing backups under dataDir/DirName.

func (*Manager) Create

func (m *Manager) Create(ctx context.Context) (Info, error)

Create takes a manual snapshot, which is never auto-pruned.

func (*Manager) CreateScheduled

func (m *Manager) CreateScheduled(ctx context.Context) (Info, error)

CreateScheduled takes a snapshot that Prune may later remove.

func (*Manager) Delete

func (m *Manager) Delete(name string) error

Delete removes one backup.

func (*Manager) List

func (m *Manager) List() ([]Info, error)

List returns every backup, newest first.

func (*Manager) Newest

func (m *Manager) Newest() (time.Time, bool, error)

Newest returns the creation time of the most recent backup, read from file names alone (no checksumming), and false when there is none.

func (*Manager) Open

func (m *Manager) Open(name string) (*os.File, Info, error)

Open returns the backup file for reading.

func (*Manager) Prune

func (m *Manager) Prune(retain int) (int, error)

Prune deletes the oldest scheduled backups beyond retain. Manual backups are never touched.

func (*Manager) Run

func (m *Manager) Run(ctx context.Context, interval time.Duration, retain int, logger *slog.Logger)

Run takes a scheduled snapshot every interval and prunes to retain. It returns when ctx is done.

func (*Manager) Verify

func (m *Manager) Verify(ctx context.Context, name string) (VerifyResult, error)

Verify re-hashes the backup against its recorded checksum, runs SQLite's integrity_check, and confirms its schema is not newer than this binary. It records the outcome next to the snapshot.

type Manifest

type Manifest struct {
	ManifestVersion int       `json:"manifest_version"`
	InstallID       string    `json:"install_id"`
	Key             string    `json:"key"`
	CreatedAt       time.Time `json:"created_at"`
	BinaryVersion   string    `json:"binary_version"`
	SchemaVersion   int       `json:"schema_version"`
	// MigrationsApplied is the row count of the snapshot's schema_migrations.
	MigrationsApplied int    `json:"migrations_applied"`
	SHA256            string `json:"sha256"`
	SizeBytes         int64  `json:"size_bytes"`
	PlainSHA256       string `json:"plain_sha256"`
	PlainSizeBytes    int64  `json:"plain_size_bytes"`
	Compression       string `json:"compression"`
	Encryption        string `json:"encryption"`
	RecipientCount    int    `json:"recipient_count"`
	// ContainsWrappedSecrets is true: the database holds secret ciphertexts and
	// wrapped data keys. IncludesMasterKey is always false.
	ContainsWrappedSecrets bool `json:"contains_wrapped_secrets"`
	IncludesMasterKey      bool `json:"includes_master_key"`
}

Manifest describes one off-box backup. It is stored unencrypted beside the ciphertext and holds no key material.

func FetchManifest

func FetchManifest(ctx context.Context, b Bucket, dataKey string) (Manifest, error)

FetchManifest downloads and parses the manifest for a ciphertext key.

func ParseManifest

func ParseManifest(data []byte) (Manifest, error)

ParseManifest decodes and sanity-checks a manifest.

type Options

type Options struct {
	Schedule      string
	DrillSchedule string
	Retention     Retention
	MaxPrune      int
	Tick          time.Duration
	RetryAfter    time.Duration
	// Grace is how late a scheduled run may be before it counts as overdue.
	Grace time.Duration
	// OrphanAge is how old an object without its partner must be before pruning removes it.
	OrphanAge time.Duration
}

Options tunes off-box backups and drills.

func DefaultOptions

func DefaultOptions() Options

DefaultOptions returns the built-in tuning: daily backups at 02:00, weekly drills.

func OptionsFromEnv

func OptionsFromEnv(lookup func(string) (string, bool)) Options

OptionsFromEnv applies env overrides to DefaultOptions.

type Remote

type Remote struct {
	Key         string    `json:"key"`
	ManifestKey string    `json:"manifest_key"`
	CreatedAt   time.Time `json:"created_at"`
	SizeBytes   int64     `json:"size_bytes"`
	// Complete is true when both the ciphertext and its manifest exist.
	Complete bool `json:"complete"`
	// Modified is the newest object modification time, used to age out orphans.
	Modified time.Time `json:"-"`
}

Remote is one backup found at the destination.

type ReplicaStatus

type ReplicaStatus struct {
	Enabled         bool       `json:"enabled"`
	IntervalSeconds int        `json:"interval_seconds"`
	LastShipAt      *time.Time `json:"last_ship_at,omitempty"`
	LastShipMs      int64      `json:"last_ship_ms,omitempty"`
	LastSizeBytes   int64      `json:"last_size_bytes,omitempty"`
	LastError       string     `json:"last_error,omitempty"`
	// PendingSince is set while the database has changes the replica does not hold yet.
	PendingSince *time.Time `json:"pending_since,omitempty"`
}

ReplicaStatus is the replica loop's state for the UI and CLI.

type Replicator

type Replicator struct {
	Svc      *Service
	DBPath   string
	Interval time.Duration
	// contains filtered or unexported fields
}

Replicator ships changed snapshots on an interval.

func (*Replicator) Run

func (r *Replicator) Run(ctx context.Context)

Run ships on every tick until ctx ends. It does nothing when Interval is zero.

func (*Replicator) Status

func (r *Replicator) Status() ReplicaStatus

Status returns a copy of the current state.

func (*Replicator) Tick

func (r *Replicator) Tick(ctx context.Context) (bool, error)

Tick ships once if the database changed since the last successful ship. It reports whether it shipped.

type ResolverDestinations

type ResolverDestinations struct{ Resolver *objectstore.Resolver }

ResolverDestinations adapts an objectstore.Resolver to Destinations.

func (ResolverDestinations) Open

func (d ResolverDestinations) Open(ctx context.Context, targetID string) (Bucket, Location, error)

Open resolves a stored destination to a client and its location.

type RestoreOptions

type RestoreOptions struct {
	// LivePath is the control plane database file to replace.
	LivePath   string
	Identities []age.Identity
	// DryRun verifies everything and leaves the live database untouched.
	DryRun bool
	// ForceInstallID accepts a backup taken by a different install.
	ForceInstallID bool
	Now            func() time.Time
	// BeforeInstall runs just before the live database is replaced; an error aborts the restore.
	BeforeInstall func() error
	// contains filtered or unexported fields
}

RestoreOptions control one restore.

type RestoreReport

type RestoreReport struct {
	Source        string   `json:"source"`
	Manifest      Manifest `json:"manifest"`
	SchemaVersion int      `json:"schema_version"`
	Checks        []Check  `json:"checks"`
	DryRun        bool     `json:"dry_run"`
	PreRestore    string   `json:"pre_restore,omitempty"`
}

RestoreReport is what a restore checked and did.

func Restore

func Restore(ctx context.Context, src Source, opts RestoreOptions) (RestoreReport, error)

Restore downloads, verifies and decrypts a backup, then swaps it in atomically. The live database file is replaced by one rename, so an interruption at any earlier point leaves the old database untouched.

func RestoreLatestReplica

func RestoreLatestReplica(ctx context.Context, b Bucket, installID string, ids []age.Identity, opts RestoreOptions) (RestoreReport, error)

RestoreLatestReplica restores the newest replica slot that verifies, falling back to the other one.

type Retention

type Retention struct {
	Daily, Weekly, Monthly int
}

Retention is how many backups to keep per calendar bucket. A backup is kept if it is the newest of any day, ISO week or month still inside its count.

func (Retention) Select

func (r Retention) Select(entries []Entry) map[string]bool

Select returns the keys to keep. It always keeps the newest entry, so a misconfigured policy can never delete the last good backup.

type Service

type Service struct {
	DB            Snapshotter
	Store         SettingsStore
	Dest          Destinations
	DataDir       string
	BinaryVersion string
	Opts          Options
	Logger        *slog.Logger
	Now           func() time.Time
	// DrillIdentities, when set, decrypt backups during drills. Their public
	// keys are added as recipients of every backup.
	DrillIdentities []age.Identity
	// Replica is the optional continuous replica loop, nil when off.
	Replica *Replicator
	// contains filtered or unexported fields
}

Service runs encrypted off-box control plane backups, restore drills and escrow.

func NewService

func NewService(db Snapshotter, st SettingsStore, dest Destinations, dataDir, binaryVersion string, opts Options, logger *slog.Logger) *Service

NewService builds a Service with the wall clock.

func (*Service) AckEscrow

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

AckEscrow records that the operator stored the bundle offline.

func (*Service) BackupRunning

func (s *Service) BackupRunning() bool

BackupRunning reports whether a backup is in progress.

func (*Service) BuildEscrow

func (s *Service) BuildEscrow(ctx context.Context, in EscrowInput) (EscrowBundle, error)

BuildEscrow encrypts the master key and other recovery files to the operator's recipients. The drill identity is never a recipient of escrow.

func (*Service) CleanTemp

func (s *Service) CleanTemp()

CleanTemp removes work directories a crashed run left behind. They can hold a plaintext snapshot, so it runs at startup when no run can be in progress.

func (*Service) DRProblem

func (s *Service) DRProblem(now time.Time) string

DRProblem lets the stale-backup alert rule fire on off-box failures and failed drills.

func (*Service) DrillRunning

func (s *Service) DrillRunning() bool

DrillRunning reports whether a drill is in progress.

func (*Service) ListRemote

func (s *Service) ListRemote(ctx context.Context) ([]Remote, error)

ListRemote lists the backups one install has at the destination, newest first.

func (*Service) Problem

func (s *Service) Problem(now time.Time) string

Problem returns a one-line description of what is wrong with the running off-box backups or drills, or "" when healthy or not enabled.

func (*Service) Run

func (s *Service) Run(ctx context.Context)

Run checks for due backups and drills every Opts.Tick until ctx is done.

func (*Service) RunBackup

func (s *Service) RunBackup(ctx context.Context, slot time.Time) (Manifest, error)

RunBackup snapshots the database, encrypts it to the configured recipients and uploads it with a manifest. slot names the schedule tick (zero for a manual run): a slot whose manifest already exists is skipped, and one whose upload was cut short is redone over the same keys.

func (*Service) RunDrill

func (s *Service) RunDrill(ctx context.Context) (DrillResult, error)

RunDrill downloads the newest complete backup and proves it can be restored, into a temporary directory, never the live database. With a drill identity configured it decrypts and integrity-checks; without one it verifies only the ciphertext checksum and manifest and reports itself as partial.

func (*Service) StartBackup

func (s *Service) StartBackup() error

StartBackup begins a manual backup in the background and returns at once. ErrBusy means one is already running.

func (*Service) StartDrill

func (s *Service) StartDrill() error

StartDrill begins a drill in the background and returns at once. ErrBusy means one is already running.

func (*Service) Status

func (s *Service) Status(ctx context.Context) (Status, error)

Status assembles the current disaster recovery state.

func (*Service) Tick

func (s *Service) Tick(ctx context.Context)

Tick runs whatever is due right now: at most one backup, then at most one drill.

func (*Service) UpdateConfig

func (s *Service) UpdateConfig(ctx context.Context, u ConfigUpdate) error

UpdateConfig validates and stores the configuration.

type SettingsStore

type SettingsStore interface {
	GetCPDRSettings(ctx context.Context) (store.CPDRSettings, error)
	UpdateCPDRConfig(ctx context.Context, s store.CPDRSettings, now time.Time) error
	SetCPDRInstallID(ctx context.Context, id string) error
	RecordCPDRBackup(ctx context.Context, at time.Time, key, runErr string) error
	RecordCPDRDrill(ctx context.Context, at time.Time, ok, partial bool, detail string, ms int64) error
	RecordCPDREscrow(ctx context.Context, at time.Time) error
	AckCPDREscrow(ctx context.Context, at time.Time) error
}

SettingsStore is the persistence surface the service needs.

type Snapshotter

type Snapshotter interface {
	SnapshotTo(ctx context.Context, dest string) (int64, string, error)
}

Snapshotter is the slice of *store.DB the manager needs.

type Source

type Source interface {
	Describe() string
	ReadManifest(ctx context.Context) (Manifest, error)
	Fetch(ctx context.Context, dst string, maxBytes int64) error
}

Source is where a restore reads an encrypted backup from.

func NewBucketSource

func NewBucketSource(b Bucket, key string) Source

NewBucketSource reads the backup at key from a bucket.

func NewFileSource

func NewFileSource(path string) Source

NewFileSource reads an encrypted backup from disk. Its manifest is the sibling file with the .json suffix.

type Status

type Status struct {
	Enabled                 bool        `json:"enabled"`
	Configured              bool        `json:"configured"`
	TargetID                string      `json:"target_id"`
	TargetName              string      `json:"target_name,omitempty"`
	InstallID               string      `json:"install_id"`
	Recipients              []string    `json:"recipients"`
	Schedule                string      `json:"schedule"`
	DrillSchedule           string      `json:"drill_schedule"`
	RetainDaily             int         `json:"retain_daily"`
	RetainWeekly            int         `json:"retain_weekly"`
	RetainMonthly           int         `json:"retain_monthly"`
	EscrowTargetID          string      `json:"escrow_target_id"`
	EscrowGeneratedAt       *time.Time  `json:"escrow_generated_at,omitempty"`
	EscrowAckedAt           *time.Time  `json:"escrow_acked_at,omitempty"`
	NextBackupAt            *time.Time  `json:"next_backup_at,omitempty"`
	NextDrillAt             *time.Time  `json:"next_drill_at,omitempty"`
	LastBackupAt            *time.Time  `json:"last_backup_at,omitempty"`
	LastBackupKey           string      `json:"last_backup_key,omitempty"`
	LastBackupError         string      `json:"last_backup_error,omitempty"`
	LastAttemptAt           *time.Time  `json:"last_attempt_at,omitempty"`
	LastDrill               DrillStatus `json:"last_drill"`
	DrillIdentityConfigured bool        `json:"drill_identity_configured"`
	BackupRunning           bool        `json:"backup_running"`
	DrillRunning            bool        `json:"drill_running"`
	Checklist               Checklist   `json:"checklist"`
	Warnings                []Warning   `json:"warnings"`
	// Replica is set only when the opt-in continuous replica is running.
	Replica *ReplicaStatus `json:"replica,omitempty"`
}

Status is the disaster recovery state shown in the UI, CLI and doctor. It carries public recipients only, never key material.

type VerifyResult

type VerifyResult struct {
	Name       string    `json:"name"`
	OK         bool      `json:"ok"`
	Checks     []Check   `json:"checks"`
	VerifiedAt time.Time `json:"verified_at"`
}

VerifyResult is the outcome of verifying one backup. Nothing is restored.

type Warning

type Warning struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

Warning is one actionable finding about the DR setup.

Jump to

Keyboard shortcuts

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