engine

package
v0.0.0-...-0137979 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package engine contains the reconcile engine: the planner (dependency DAG + waves), the level-triggered reconcile pass, prune, and the work queue.

Index

Constants

This section is empty.

Variables

View Source
var DefaultWaves = map[string]int{
	"machine":    0,
	"swarmnode":  10,
	"credential": 20,
	"secret":     20,
	"config":     25,
	"volume":     30,
	"network":    40,
	"dnszone":    50,
	"dnsrecord":  50,
	"service":    60,
	"app":        60,
	"ingress":    70,
	"wafruleset": 70,
}

DefaultWaves orders kinds across infrastructure layers when no explicit dependsOn edge applies. Lower waves are reconciled first. Unlisted kinds default to 100.

Functions

This section is empty.

Types

type Engine

type Engine struct {
	Reg    *provider.Registry
	State  State
	Logger *slog.Logger

	// PruneMode controls how far prune goes: off, dry-run (log only) or on.
	PruneMode PruneMode
	// PruneGrace is how long an object must stay continuously absent from the desired
	// set before prune will delete it. It absorbs transient source blips: a candidate
	// that reappears has its clock reset. Zero disables the grace period.
	PruneGrace time.Duration
	// PruneFloor is the maximum fraction of the known inventory that prune may delete
	// in a single pass (0..1). A pass that would prune more is refused as a safety guard.
	// Zero means "no floor" (prune anything).
	PruneFloor float64
	// AllowEmptyPrune permits pruning when the desired set is empty (default false).
	AllowEmptyPrune bool
}

Engine reconciles a desired set of objects against registered providers.

func (*Engine) DeleteObject

func (e *Engine) DeleteObject(ctx context.Context, kind, name string) error

DeleteObject deletes a single object's live resource and removes its persisted status.

func (*Engine) DesiredKeys

func (e *Engine) DesiredKeys(objs []model.Object) (map[string]bool, error)

DesiredKeys returns the canonical key set for a desired object list, expanding high-level kinds first. Prune correctness depends on this matching exactly what Reconcile computes, so both call it.

func (*Engine) Desugar

func (e *Engine) Desugar(objs []model.Object) ([]model.Object, error)

Desugar expands high-level objects (whose provider implements Desugarer) into core objects. One level of expansion is performed.

func (*Engine) PlanPrune

func (e *Engine) PlanPrune(ctx context.Context, desiredKeys map[string]bool, record bool) (PruneReport, error)

PlanPrune computes the prune report for a desired key set without mutating the live world. It does record StaleSince on newly-stale objects (the grace clock has to start somewhere) unless record is false.

func (*Engine) PruneNow

func (e *Engine) PruneNow(ctx context.Context, rep PruneReport) (int, error)

PruneNow deletes the eligible candidates of an already-computed report. It is the explicit, operator-driven path (`crane prune --confirm`) and runs regardless of the configured PruneMode — the report it is handed has already passed every guard.

func (*Engine) Reconcile

func (e *Engine) Reconcile(ctx context.Context, desired []model.Object, opts Options) ([]Result, error)

Reconcile runs a full level-triggered pass over the desired objects.

type Options

type Options struct {
	DryRun bool // compute plan only, do not Apply or prune
	// Prune runs the prune stage at the engine's configured PruneMode. It is a
	// per-pass opt-in: a partial apply (`crane apply -f one.yaml`) must never prune,
	// because its desired set is not the whole world.
	Prune bool
}

Options controls a reconcile pass.

type Plan

type Plan struct {
	Order []model.Object
}

Plan is a topologically-ordered set of objects.

func BuildPlan

func BuildPlan(objs []model.Object) (Plan, error)

BuildPlan topologically sorts objects using explicit dependsOn edges, breaking ties by ascending wave then kind/name for stability. Returns an error on dependency cycles.

type PruneCandidate

type PruneCandidate struct {
	Ref model.Ref `json:"ref"`
	// StaleSince is when the object first went missing from the desired set.
	StaleSince time.Time `json:"staleSince,omitempty"`
	// StaleFor is StaleSince rendered as a duration for humans/JSON consumers.
	StaleFor string `json:"staleFor,omitempty"`
	// Eligible reports whether this candidate passes the grace period and the
	// ownership check, i.e. whether prune-on would delete it right now.
	Eligible bool `json:"eligible"`
	// Reason explains the disposition — why it will be deleted, or why not.
	Reason string `json:"reason"`
	// Exists reports whether the live resource is still there. A candidate that
	// no longer exists only needs its state entry dropped.
	Exists bool `json:"exists"`
	// Owner is the io.craneops.owner label read off the live resource, if any.
	Owner string `json:"owner,omitempty"`
}

PruneCandidate is one object in the prune inventory that is no longer desired.

type PruneMode

type PruneMode string

PruneMode controls how far a reconcile pass takes prune. Prune is the only destructive thing the engine does, so it is rolled out in stages rather than toggled: Off computes nothing, DryRun computes and logs the candidate set without touching the live world, and On actually deletes.

const (
	// PruneOff disables prune entirely (default).
	PruneOff PruneMode = "off"
	// PruneDryRun computes the prune plan, applies every guard, and logs what
	// *would* be deleted — but deletes nothing.
	PruneDryRun PruneMode = "dry-run"
	// PruneOn deletes eligible stale objects.
	PruneOn PruneMode = "on"
)

func ParsePruneMode

func ParsePruneMode(s string) (PruneMode, error)

ParsePruneMode parses a mode string, accepting the legacy boolean spellings.

func (PruneMode) Destructive

func (m PruneMode) Destructive() bool

Destructive reports whether the mode actually deletes.

type PruneReport

type PruneReport struct {
	Mode PruneMode `json:"mode"`
	// Inventory is the number of objects crane knows about (the state store).
	Inventory int `json:"inventory"`
	// Desired is the number of objects in the source's desired set.
	Desired int `json:"desired"`
	// Candidates are the inventory entries absent from the desired set.
	Candidates []PruneCandidate `json:"candidates,omitempty"`
	// Refused, when non-empty, is why a global guard vetoed the whole prune.
	Refused string `json:"refused,omitempty"`
	// Grace is the configured grace period.
	Grace string `json:"grace,omitempty"`
}

PruneReport is the full outcome of planning a prune. It is what `crane prune` and the dry-run log render, and it is computed identically whether prune is off, dry-run or on — so what you preview is exactly what you get.

func (PruneReport) Eligible

func (r PruneReport) Eligible() []PruneCandidate

Eligible returns the candidates prune-on would act on right now.

type Queue

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

Queue is a debounced, deduplicating trigger for reconcile passes. Multiple Notify calls within the debounce window coalesce into a single pass. It is the single funnel through which all sources (git, webhook, local dir, timer, API) request work.

func NewQueue

func NewQueue(debounce time.Duration) *Queue

NewQueue creates a Queue with the given debounce window.

func (*Queue) Notify

func (q *Queue) Notify()

Notify requests a reconcile pass. It is non-blocking and coalesces with other pending notifications.

func (*Queue) Run

func (q *Queue) Run(ctx context.Context, fn func(context.Context))

Run consumes notifications and invokes fn for each coalesced batch until ctx is done. A periodic resync can be wired by calling Notify on a ticker.

type Result

type Result struct {
	Ref     model.Ref         `json:"ref"`
	Phase   string            `json:"phase"`
	Actions []provider.Action `json:"actions,omitempty"`
	Drifted bool              `json:"drifted"`
	Blocked []string          `json:"blocked,omitempty"`
	Error   string            `json:"error,omitempty"`
}

Result is the outcome for a single object in a reconcile pass.

type State

type State interface {
	Load(kind, name string) (model.Status, error)
	Save(kind, name string, st model.Status) error
	Delete(kind, name string) error
	List() ([]model.Ref, error)
}

State persists per-object Status and doubles as the prune inventory: the set of known status entries is exactly the set of objects CraneOps has applied.

Jump to

Keyboard shortcuts

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