localbackupschedule

package
v0.43.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package localbackupschedule lowers the CUE-governed UTC backup cadence to a bounded pair of local systemd units. It owns no plan or owner authority and never invokes the backup runtime directly.

Index

Constants

View Source
const AuthorizationArchiveDirectory = ".stackkit/backups/schedule/authorization-archive"
View Source
const AuthorizationPath = ".stackkit/backups/schedule/authorization.json"

Variables

View Source
var (
	ErrSystemdUnavailable = errors.New("local backup scheduling requires an active local systemd manager")
	ErrUnitNotInstalled   = errors.New("local backup schedule units are not installed")
)

Functions

func LatestSlot

func LatestSlot(schedule localbackuppolicy.Schedule, now time.Time) (time.Time, error)

LatestSlot returns the most recent governed UTC slot at or before now. It deliberately does not apply timer jitter: jitter affects when systemd starts the service, while the scheduled operation remains bound to the deterministic cadence slot.

Types

type Authorization

type Authorization struct {
	APIVersion string                                  `json:"apiVersion"`
	Binding    AuthorizationBinding                    `json:"binding"`
	State      string                                  `json:"state"`
	ApprovedAt time.Time                               `json:"approvedAt"`
	ChangedAt  time.Time                               `json:"changedAt"`
	Execution  *ScheduledExecution                     `json:"execution,omitempty"`
	Signature  localevidence.OwnerPolicyStateSignature `json:"signature"`
}

func ActivateAuthorization

func ActivateAuthorization(workspace string, binding AuthorizationBinding) (Authorization, error)

func BeginScheduledAttempt

func BeginScheduledAttempt(workspace string, current AuthorizationBinding) (record Authorization, noOp bool, returnErr error)

BeginScheduledAttempt durably names the governed UTC slot before any snapshot. Callers cannot choose a slot or operation ID. A pending attempt is resumed even when a later timer fires; noOp means no new snapshot is due.

func CompleteScheduledAttempt

func CompleteScheduledAttempt(workspace string, current AuthorizationBinding, anchor backuplifecycle.SnapshotAnchor) (Authorization, error)

func DisableAuthorization

func DisableAuthorization(workspace string, ownerApproved bool) (Authorization, error)

DisableAuthorization revokes local dispatch before any timer is disabled. It needs current Owner custody, but never needs the old runtime to be alive.

func LoadAuthorization

func LoadAuthorization(workspace string) (Authorization, error)

func PrepareAuthorization

func PrepareAuthorization(workspace string, binding AuthorizationBinding, ownerApproved bool) (Authorization, error)

PrepareAuthorization persists approval before a trigger is installed. A prepared authorization cannot execute; activation follows trigger readback. The caller holds the shared lifecycle mutation lock throughout installation.

func RequireAuthorization

func RequireAuthorization(workspace string, current AuthorizationBinding) (Authorization, error)

RequireAuthorization fails closed when a schedule is stale, disabled or the CLI bytes changed. The binding supplied here must come from current local authority, never directly from the persisted record.

type AuthorizationBinding

type AuthorizationBinding struct {
	OwnerRef      string                           `json:"ownerRef"`
	AuthorityRef  string                           `json:"authorityRef"`
	Lineage       backuplifecycle.AuthorityLineage `json:"lineage"`
	PolicyDigest  string                           `json:"policyDigest"`
	WorkspaceRoot string                           `json:"workspaceRoot"`
	SpecPath      string                           `json:"specPath"`
	ProcessUID    string                           `json:"processUid"`
	CLI           clibinding.Identity              `json:"cli"`
	Schedule      localbackuppolicy.Schedule       `json:"schedule"`
	UnitName      string                           `json:"unitName"`
	UnitDigest    string                           `json:"unitDigest"`
}

AuthorizationBinding is a projection of already verified local Apply and backup authority. A trigger cannot supply or widen any of these fields.

type ExecRunner

type ExecRunner struct{}

ExecRunner invokes one fixed systemctl argv directly and bounds the call. It never runs a shell and is intentionally separate from the backup CLI process that the rendered service will execute later.

func (ExecRunner) Run

func (ExecRunner) Run(parent context.Context, argv []string) ([]byte, error)

type InitObserver

InitObserver is the shared hostconformance observation boundary. Production callers should leave it nil so the package observes the local host through hostconformance.ObserveInitSystem; tests may inject a deterministic fact.

type Options

type Options struct {
	Runner        Runner
	ObserveInit   InitObserver
	CurrentUID    ProcessUID
	UnitDirectory string
}

Options configures the local command and filesystem boundaries. Unit names remain package-owned; UnitDirectory is intended for an injected test root and defaults to the system unit directory in production.

type ProcessUID

type ProcessUID func() (string, error)

ProcessUID resolves the effective UID that will be written to systemd's User=. Production uses the numeric effective UID and never a caller supplied username.

type RenderRequest

type RenderRequest struct {
	WorkspacePath string
	SpecPath      string
	Schedule      localbackuppolicy.Schedule
	CLI           interface {
		Path() string
		Verify() error
	}
}

RenderRequest contains already resolved, owner-independent inputs. The schedule is the shared localbackuppolicy value; this package does not add defaults or parse arbitrary cron expressions.

type RenderedUnits

type RenderedUnits struct {
	Names         UnitNames
	ServicePath   string
	TimerPath     string
	ServiceBytes  []byte
	TimerBytes    []byte
	WorkspacePath string
	SpecPath      string
	// ProcessUID is the numeric effective UID used by User=.
	ProcessUID string
}

RenderedUnits is the complete canonical unit pair and its confined paths. Unit bytes contain only paths, a process user, and the resolved UTC cadence; no credentials or owner material are included.

func (RenderedUnits) Digest

func (units RenderedUnits) Digest() string

Digest returns the secret-free digest of both rendered unit files. The separator keeps the pair boundary unambiguous and lets an authority bind the exact service/timer bytes as one artifact.

type Runner

type Runner interface {
	Run(context.Context, []string) ([]byte, error)
}

Runner is the narrow command boundary for systemctl. Implementations must execute argv directly without a shell; the production runner applies its own short timeout and the package never sends backup-runtime commands here.

type ScheduledExecution

type ScheduledExecution struct {
	Slot             time.Time `json:"slot"`
	OperationID      string    `json:"operationId"`
	State            string    `json:"state"`
	SnapshotAnchorID string    `json:"snapshotAnchorId,omitempty"`
	// ApprovedAt retains the original slot grant when a later explicit
	// CLI/unit reapproval resumes this same runtime operation.
	ApprovedAt time.Time `json:"approvedAt,omitzero"`
}

ScheduledExecution records an attempt through the ordinary backup lifecycle. A pending attempt is resumed with the same operation ID, even after its UTC slot has passed. Only a verified SnapshotAnchor can complete it.

type Scheduler

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

Scheduler renders and controls one workspace-bound local backup timer. Owner approval and signed plan state are deliberately outside this package.

func New

func New(options Options) *Scheduler

New creates a scheduler with the shared host fact and direct command boundaries. It performs no observation, file write, or systemd mutation.

func (*Scheduler) Disable

func (s *Scheduler) Disable(ctx context.Context, workspace string) error

Disable idempotently disables and stops the workspace timer. Unit files are retained for an explicit re-enable or a later owner-authorized replacement.

func (*Scheduler) Enable

func (s *Scheduler) Enable(ctx context.Context, request RenderRequest) error

Enable idempotently enables and starts the exact workspace timer after checking that the installed unit bytes still match the requested CLI, workspace, user, and schedule.

func (*Scheduler) Install

func (s *Scheduler) Install(ctx context.Context, request RenderRequest) (RenderedUnits, error)

Install writes the exact unit pair and reloads the observed local systemd manager. It does not enable or start the timer; callers must perform that owner-approved action explicitly through Enable.

func (*Scheduler) Render

func (s *Scheduler) Render(request RenderRequest) (RenderedUnits, error)

Render produces the exact service and timer files without requiring an active systemd manager. Installation, enabling, and status each perform the live prerequisite observation separately before their side effect or readback.

func (*Scheduler) Status

func (s *Scheduler) Status(ctx context.Context, workspace string) (UnitStatus, error)

Status reads the exact workspace timer without enabling, disabling, or changing any unit.

func (*Scheduler) VerifyInstalled

func (s *Scheduler) VerifyInstalled(request RenderRequest) error

VerifyInstalled re-renders the exact request and checks both unit files. Scheduled invocations use this immediately before their lifecycle call so a replaced CLI, workspace, spec path, or cadence cannot be silently used.

type UnitNames

type UnitNames struct {
	Service string `json:"service"`
	Timer   string `json:"timer"`
}

UnitNames identifies the fixed service/timer pair derived from a workspace. The workspace digest prevents two local stacks from silently sharing a timer while keeping the unit identity independent of mutable plan fields.

func UnitNamesForWorkspace

func UnitNamesForWorkspace(workspace string) (UnitNames, error)

UnitNamesForWorkspace derives the package-owned unit identity without requiring the workspace to exist. Disable and status use this for cleanup and diagnostics after a workspace has been moved or removed.

type UnitStatus

type UnitStatus struct {
	Names        UnitNames `json:"names"`
	EnabledState string    `json:"enabledState"`
	ActiveState  string    `json:"activeState"`
	Enabled      bool      `json:"enabled"`
	Active       bool      `json:"active"`
}

UnitStatus is a read-only systemd status snapshot for one workspace timer. State values are normalized closed vocabulary; command diagnostics are not copied into the result.

Jump to

Keyboard shortcuts

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