Documentation
¶
Index ¶
- type Controller
- func (c *Controller) EnqueueBackup(ctx context.Context, host, template, slug string, opts extension.BackupOptions) (string, error)
- func (c *Controller) LastBackupAt(ctx context.Context, host, template, slug string) (time.Time, error)
- func (c *Controller) ListBackupInstances(ctx context.Context) ([]extension.BackupInstance, error)
- type Service
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Controller ¶
Controller is the core-side implementation of extension.BackupController. It projects backup-eligible instances, reports last-success times, and enqueues backup jobs over the same path as the HTTP POST /backups handler.
func (*Controller) EnqueueBackup ¶
func (c *Controller) EnqueueBackup(ctx context.Context, host, template, slug string, opts extension.BackupOptions) (string, error)
EnqueueBackup enqueues a backup job for one instance, deduping against a backup already queued/running/reconciling for the same instance WHOSE SCOPE COVERS the requested one.
The scope is validated BEFORE the dedupe check, deliberately. The other order answers a misconfigured scheduler — a typo'd volume name, or one newly marked `backup: none` — with the documented "already in flight, nothing to do" (`"", nil`), which a scheduler records as a handled tick. The misconfiguration then stays invisible for as long as backups keep overlapping, while the volume the scheduler believes it is protecting is never captured. A bad scope is a bad scope whether or not a run happens to be in flight.
Coverage, not mere per-instance presence, is what the dedupe keys on. Per instance was safe while every enqueue for an instance requested the same work; with scopes it is not — a `{Volumes:["wal"]}` tick landing during an unscoped nightly run would get `("", nil)`, "already handled", for work that run does do, but a `{Volumes:["wal"]}` tick landing during a `{Volumes:["data"]}` run would get the same answer for work nobody is doing. That window's snapshot is then never taken and never retried, silently.
func (*Controller) LastBackupAt ¶
func (c *Controller) LastBackupAt(ctx context.Context, host, template, slug string) (time.Time, error)
LastBackupAt returns the finish time of the newest complete backup for an instance, or the zero time if none exists. ListBackups is newest-first, so the first complete row wins.
func (*Controller) ListBackupInstances ¶
func (c *Controller) ListBackupInstances(ctx context.Context) ([]extension.BackupInstance, error)
ListBackupInstances walks every known host, lists its live instances, and returns those whose template declares at least one backup-marked volume. A per-host listing failure is logged and skipped rather than aborting the whole sweep, so one unreachable host doesn't starve backups on the others.
type Service ¶
type Service interface {
Hosts() []config.Host
ListAllInstances(ctx context.Context, host string) ([]instance.Observed, error)
GetTemplate(ctx context.Context, id string) (store.Template, error)
ListBackups(ctx context.Context, host, template, slug string, limit int) ([]store.Backup, error)
CheckBackupable(ctx context.Context, host, template, slug string, volumes []string) error
CheckBackupScopeDeclared(ctx context.Context, host, template, slug string, volumes []string) error
}
Service is the slice of *instance.Service the controller needs. Declaring it as an interface keeps the controller unit-testable with a fake.