janitor

package
v0.8.6 Latest Latest
Warning

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

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

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

View Source
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

AllStages lists every stage in the order a pass runs them.

View Source
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

func SavePolicy(ctx context.Context, s PolicyStore, p Policy, actor string, now time.Time) error

SavePolicy validates and stores p.

Types

type Controller

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

Controller runs scheduled passes from the reconcile loop.

func NewController

func NewController(e *Engine) *Controller

NewController wraps e.

func (*Controller) Name

func (c *Controller) Name() string

Name implements reconcile.Controller.

func (*Controller) Reconcile

func (c *Controller) Reconcile(ctx context.Context) (reconcile.Result, error)

Reconcile implements reconcile.Controller.

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.

func New

func New(d Deps) *Engine

New builds an Engine.

func (*Engine) Due

func (e *Engine) Due(p Policy) bool

Due reports whether a scheduled pass should run now.

func (*Engine) History

func (e *Engine) History(ctx context.Context, limit int) ([]Report, error)

History returns the newest runs.

func (*Engine) Run

func (e *Engine) Run(ctx context.Context, opts Options) (Report, error)

Run executes one pass under the saved policy and records it in history.

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 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
}

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

func (p Policy) StageEnabled(s Stage) bool

StageEnabled reports whether the policy lets s run.

func (Policy) Validate

func (p Policy) Validate() error

Validate rejects values that would make a pass unsafe or meaningless.

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"`
}

Report is one pass.

type Stage

type Stage string

Stage names one cleanup category.

const (
	StageContainers Stage = "containers"
	StageImages     Stage = "images"
	StageBuildCache Stage = "build_cache"
	StageVolumes    Stage = "volumes"
	StageAttempts   Stage = "deploy_attempts"
	StageTokens     Stage = "api_tokens"
)

Cleanup stages.

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.

Jump to

Keyboard shortcuts

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