Documentation
¶
Overview ¶
Package janitor runs bounded, level-triggered cleanup passes on the control plane's own node: unused Docker data, build cache over budget, orphaned volumes (quarantined first) and old failed deploy attempts.
Index ¶
- Constants
- Variables
- func PurgeTokens(ctx context.Context, p TokenPurger, kind store.TokenPurgeKind, days int, ...) (int, error)
- func SavePolicy(ctx context.Context, s PolicyStore, p Policy, actor string, now time.Time) error
- func SetVolumeProtector(fn func(name string) (bool, string))
- type Actor
- type Controller
- type Deps
- type Docker
- type Engine
- type IgnoredItem
- type Item
- type ItemSelection
- type Options
- type Policy
- type PolicyStore
- type Report
- type Stage
- type StageResult
- type Store
- type TokenPurger
- type TokenWindows
Constants ¶
const ( ActorUser = "user" ActorToken = "api_token" ActorSchedule = "schedule" )
Actor kinds recorded on a run.
const ( ActionRemoved = "removed" ActionWouldRemove = "would_remove" ActionQuarantined = "quarantined" ActionWouldQuarantine = "would_quarantine" ActionKept = "kept" StatusRan = "ran" StatusSkipped = "skipped" StatusFailed = "failed" TriggerScheduled = "scheduled" TriggerManual = "manual" TriggerDiskFix = "disk_fix" TriggerNodeGuardrail = "node_guardrail" // AuditTokensCleanup is the audit action written once per token cleanup run. AuditTokensCleanup = "tokens.cleanup" )
Item actions a stage reports.
Variables ¶
var AllStages = []Stage{StageContainers, StageImages, StageBuildCache, StageVolumes, StageAttempts, StageTokens}
AllStages lists every stage in the order a pass runs them.
var ErrBusy = errors.New("janitor: a cleanup pass is already running")
ErrBusy means another pass is already running.
Functions ¶
func PurgeTokens ¶
func PurgeTokens(ctx context.Context, p TokenPurger, kind store.TokenPurgeKind, days int, now time.Time, batch, maxBatches int, dryRun bool) (int, error)
PurgeTokens deletes tokens of kind older than days, in batches of batch up to maxBatches, and returns the total. With dryRun it counts one capped sweep.
func SavePolicy ¶
SavePolicy validates and stores p.
func SetVolumeProtector ¶
SetVolumeProtector installs the boot-time database volume lock the volumes stage consults on top of the built-in db- rule. Janitor cannot import api.
Types ¶
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller runs scheduled passes from the reconcile loop.
type Deps ¶
type Deps struct {
Store Store
Docker Docker
// DiskFree reports free and total bytes of the volume Docker data lives on.
DiskFree func(ctx context.Context) (free, total int64, err error)
// DesiredContainers lists container names the reconciler still wants, which a prune must keep.
DesiredContainers func(ctx context.Context) ([]string, error)
// OrphanVolumes lists named volumes no desired state or container references.
OrphanVolumes func(ctx context.Context) ([]docker.NamedVolume, error)
RemoveVolume func(ctx context.Context, name string) error
// TokenWindows reads the live token retention settings; nil skips the tokens stage.
TokenWindows func(ctx context.Context) TokenWindows
// TokenBatch and TokenMaxBatches bound one pass; zero uses the defaults.
TokenBatch, TokenMaxBatches int
// Audit records a system audit row with a JSON detail.
Audit func(ctx context.Context, action, detail string)
Logger *slog.Logger
Now func() time.Time
}
Deps are the engine's collaborators.
type Docker ¶
type Docker interface {
DiskUsage(ctx context.Context) (docker.DiskUsage, error)
ListAllImages(ctx context.Context) ([]docker.ImageRecord, error)
PruneContainers(ctx context.Context, keep []string) (docker.PruneContainersResult, error)
PruneDanglingImages(ctx context.Context) (docker.PruneImagesResult, error)
PruneAnonymousVolumes(ctx context.Context) (docker.PruneVolumesResult, error)
BuildCacheRecords(ctx context.Context) ([]docker.BuildCacheRecord, error)
PruneBuildCacheOlderThan(ctx context.Context, olderThan time.Duration) (docker.PruneBuildCacheResult, error)
}
Docker is the daemon surface a pass uses. *docker.Client satisfies it.
type Engine ¶
type Engine struct {
Deps
// contains filtered or unexported fields
}
Engine runs cleanup passes one at a time.
type IgnoredItem ¶
type IgnoredItem struct {
Stage Stage `json:"stage"`
Name string `json:"name"`
Reason string `json:"reason"`
}
IgnoredItem is an allowlist entry a pass did not act on, and why.
type Item ¶
type Item struct {
Name string `json:"name"`
Detail string `json:"detail,omitempty"`
SizeBytes int64 `json:"size_bytes"`
// Count is how many rows the item covers, for stages that remove rows rather than bytes.
Count int `json:"count,omitempty"`
Action string `json:"action"`
}
Item is one thing a stage removed, would remove, or deliberately kept.
type ItemSelection ¶
ItemSelection lists the item names one stage may act on.
type Options ¶
type Options struct {
Trigger string
DryRun bool
// Force runs the size-driven stages even when free space is above budget.
Force bool
// Stages limits the pass to these stages; empty runs every stage the policy enables.
Stages []Stage
// Items, when set, limits the pass to the listed items; it replaces Stages.
Items []ItemSelection
Actor *Actor
}
Options say how one pass runs.
type Policy ¶
type Policy struct {
Enabled bool `json:"enabled"`
// DryRun makes scheduled passes report without removing anything.
DryRun bool `json:"dry_run"`
IntervalMinutes int `json:"interval_minutes"`
// DiskFreeBudgetPercent is the free space below which size-driven stages run on a schedule.
DiskFreeBudgetPercent float64 `json:"disk_free_budget_percent"`
BuildCacheBudgetMB int64 `json:"build_cache_budget_mb"`
BuildCacheMaxAgeHours int `json:"build_cache_max_age_hours"`
// VolumeQuarantineDays is how long an orphaned volume is held before it may be deleted.
VolumeQuarantineDays int `json:"volume_quarantine_days"`
// DeleteOrphanVolumes lets a pass delete volumes whose quarantine ended; off keeps them listed only.
DeleteOrphanVolumes bool `json:"delete_orphan_volumes"`
AttemptRetentionDays int `json:"attempt_retention_days"`
AttemptKeepPerApp int `json:"attempt_keep_per_app"`
DisabledStages []Stage `json:"disabled_stages"`
}
Policy is the operator-editable cleanup configuration.
func DefaultPolicy ¶
func DefaultPolicy() Policy
DefaultPolicy reports only until an operator turns removal on.
func LoadPolicy ¶
func LoadPolicy(ctx context.Context, s PolicyStore) (Policy, error)
LoadPolicy returns the saved policy, or the default when none was saved.
func (Policy) StageEnabled ¶
StageEnabled reports whether the policy lets s run.
type PolicyStore ¶
type PolicyStore interface {
GetJanitorPolicy(ctx context.Context) (string, bool, error)
SetJanitorPolicy(ctx context.Context, body, actor string, now time.Time) error
}
PolicyStore persists the policy as JSON.
type Report ¶
type Report struct {
ID string `json:"id"`
StartedAt time.Time `json:"started_at"`
Trigger string `json:"trigger"`
DryRun bool `json:"dry_run"`
FreePercent float64 `json:"free_percent"`
Pressure bool `json:"pressure"`
Stages []StageResult `json:"stages"`
ReclaimedBytes int64 `json:"reclaimed_bytes"`
Error string `json:"error,omitempty"`
// Actor is who started the pass; absent on runs recorded before it was tracked.
Actor *Actor `json:"actor,omitempty"`
// Ignored lists allowlist entries the pass did not act on.
Ignored []IgnoredItem `json:"ignored_items,omitempty"`
}
Report is one pass.
type StageResult ¶
type StageResult struct {
Stage Stage `json:"stage"`
Status string `json:"status"`
Reason string `json:"reason,omitempty"`
Items []Item `json:"items"`
ReclaimedBytes int64 `json:"reclaimed_bytes"`
Error string `json:"error,omitempty"`
}
StageResult is what one stage did in a pass.
type Store ¶
type Store interface {
PolicyStore
InsertJanitorRun(ctx context.Context, r store.JanitorRun, keep int) error
ListJanitorRuns(ctx context.Context, limit int) ([]store.JanitorRun, error)
UpsertJanitorQuarantine(ctx context.Context, q store.JanitorQuarantine) error
ListJanitorQuarantine(ctx context.Context, kind string) ([]store.JanitorQuarantine, error)
DeleteJanitorQuarantine(ctx context.Context, kind, name string) error
ListPrunableDeployAttempts(ctx context.Context, cutoff time.Time, keep, limit int) ([]store.PrunableAttempt, error)
DeleteDeployAttempts(ctx context.Context, ids []string) error
TokenPurger
}
Store is the persistence a pass needs. *store.DB satisfies it.
type TokenPurger ¶
type TokenPurger interface {
PurgeInactiveAPITokens(ctx context.Context, kind store.TokenPurgeKind, cutoff time.Time, limit int, dryRun bool) (int, error)
}
TokenPurger deletes inactive API tokens. *store.DB satisfies it.
type TokenWindows ¶
type TokenWindows struct{ Revoked, Expired int }
TokenWindows are the retention windows in days; 0 keeps that kind forever.