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
- Variables
- func LatestSlot(schedule localbackuppolicy.Schedule, now time.Time) (time.Time, error)
- type Authorization
- func ActivateAuthorization(workspace string, binding AuthorizationBinding) (Authorization, error)
- func BeginScheduledAttempt(workspace string, current AuthorizationBinding) (record Authorization, noOp bool, returnErr error)
- func CompleteScheduledAttempt(workspace string, current AuthorizationBinding, ...) (Authorization, error)
- func DisableAuthorization(workspace string, ownerApproved bool) (Authorization, error)
- func LoadAuthorization(workspace string) (Authorization, error)
- func PrepareAuthorization(workspace string, binding AuthorizationBinding, ownerApproved bool) (Authorization, error)
- func RequireAuthorization(workspace string, current AuthorizationBinding) (Authorization, error)
- type AuthorizationBinding
- type ExecRunner
- type InitObserver
- type Options
- type ProcessUID
- type RenderRequest
- type RenderedUnits
- type Runner
- type ScheduledExecution
- type Scheduler
- func (s *Scheduler) Disable(ctx context.Context, workspace string) error
- func (s *Scheduler) Enable(ctx context.Context, request RenderRequest) error
- func (s *Scheduler) Install(ctx context.Context, request RenderRequest) (RenderedUnits, error)
- func (s *Scheduler) Render(request RenderRequest) (RenderedUnits, error)
- func (s *Scheduler) Status(ctx context.Context, workspace string) (UnitStatus, error)
- func (s *Scheduler) VerifyInstalled(request RenderRequest) error
- type UnitNames
- type UnitStatus
Constants ¶
const AuthorizationArchiveDirectory = ".stackkit/backups/schedule/authorization-archive"
const AuthorizationPath = ".stackkit/backups/schedule/authorization.json"
Variables ¶
var ( ErrUnitNotInstalled = errors.New("local backup schedule units are not installed") )
Functions ¶
func LatestSlot ¶
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.
type InitObserver ¶
type InitObserver func(context.Context) hostconformance.InitSystemFacts
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.