fixit

package
v0.8.8 Latest Latest
Warning

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

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

Documentation

Overview

Package fixit turns failing readiness and diagnostic checks into typed, previewable, verifiable fixes with attempt memory and loop protection.

Index

Constants

View Source
const (
	RunSystemd = "systemd"
	RunDocker  = "docker"
	RunDev     = "dev"
)

Run modes the control plane can be started in.

View Source
const DefaultMaxPerHour = 3

DefaultMaxPerHour caps mutating applies per fix per hour.

Variables

View Source
var ErrCannotFixHere = errors.New("fixit: cannot be fixed from here")

ErrCannotFixHere is returned by a fix's Run when this host cannot be repaired from inside the control plane.

View Source
var ErrUnknownFix = errors.New("fixit: unknown fix")

ErrUnknownFix is returned for an id that is not registered.

Functions

func Fingerprint

func Fingerprint(checkID string, a Applicability) string

Fingerprint identifies one failing check result.

func ValidAdvertiseHost

func ValidAdvertiseHost(h string) error

ValidAdvertiseHost accepts a hostname or a non-loopback IP, never a URL or port.

Types

type Applicability

type Applicability struct {
	// Failing is true while the originating check does not pass.
	Failing bool `json:"failing"`
	// Detail is the check result as a person reads it.
	Detail string `json:"detail"`
	// Signature feeds the fingerprint; empty means Detail. Set it when Detail
	// carries volatile numbers that should not re-arm a demoted fix.
	Signature string `json:"-"`
	// Kind lowers the fix's tier for this host; empty keeps Fix.Kind.
	Kind    Kind     `json:"kind,omitempty"`
	Reason  string   `json:"reason,omitempty"`
	Changes []Change `json:"changes"`
	Command string   `json:"command,omitempty"`
	Param   *Param   `json:"param,omitempty"`
}

Applicability is what a fix's Detect found out about the host right now. It doubles as the re-verification result after an apply.

type Attempt

type Attempt struct {
	FixID       string        `json:"fix_id"`
	Subject     string        `json:"subject"`
	At          time.Time     `json:"at"`
	Actor       string        `json:"actor"`
	Outcome     OutcomeStatus `json:"outcome"`
	Detail      string        `json:"detail"`
	Fingerprint string        `json:"fingerprint"`
}

Attempt is one persisted apply or re-check.

type BackupDeps

type BackupDeps struct {
	Check func(ctx context.Context) (CheckState, error)
	// Create takes a snapshot and returns its name; nil means backups are not configured.
	Create func(ctx context.Context) (string, error)
}

BackupDeps are the facts and the action the stale-backup fix uses.

type Change

type Change struct {
	Label  string `json:"label"`
	Detail string `json:"detail,omitempty"`
	Bytes  int64  `json:"bytes,omitempty"`
}

Change is one thing an apply would do, shown before it happens.

type CheckState

type CheckState struct {
	Failing bool
	Detail  string
}

CheckState is a check result reduced to what a fix needs.

type DiskDeps

type DiskDeps struct {
	Free        func(ctx context.Context) (free, total int64, err error)
	Reclaimable func(ctx context.Context) (DiskReclaim, error)
	Prune       func(ctx context.Context) (freed int64, err error)
	// WarnFreePercent is the free-space percentage below which the check fails.
	WarnFreePercent float64
}

DiskDeps are the facts and the pruner the disk fix uses.

type DiskReclaim

type DiskReclaim struct {
	ContainersBytes int64
	ImagesBytes     int64
	VolumesBytes    int64
	BuildCacheBytes int64
	OrphanNetworks  []string
}

DiskReclaim is what a cleanup would free, by category.

type Engine

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

Engine is the registry plus the apply state machine.

func NewEngine

func NewEngine(store Store, opts ...EngineOption) *Engine

NewEngine builds an engine over an attempt store.

func (*Engine) Apply

func (e *Engine) Apply(ctx context.Context, id, actor string, params map[string]string) (Result, error)

Apply runs the fix (auto tier) or re-checks it (guided and manual tiers), then re-verifies by re-running the originating check. It never runs a mutation the demotion or rate limit has withdrawn.

func (*Engine) List

func (e *Engine) List(ctx context.Context, subject string, includeHealthy bool) ([]View, error)

List returns fixes for a subject ("" for all). Healthy fixes are left out unless includeHealthy is set. Listing re-runs each check but never mutates.

func (*Engine) Preview

func (e *Engine) Preview(ctx context.Context, id string) (View, error)

Preview returns one fix's current plan without changing anything.

func (*Engine) Register

func (e *Engine) Register(f Fix) error

Register adds a fix. An auto fix without Run is a programming error.

type EngineOption

type EngineOption func(*Engine)

EngineOption configures an Engine.

func WithClock

func WithClock(now func() time.Time) EngineOption

WithClock overrides the time source, for tests.

func WithMaxPerHour

func WithMaxPerHour(n int) EngineOption

WithMaxPerHour overrides the per-fix hourly apply cap; zero keeps the default.

type Finding

type Finding struct {
	Failing bool
	Detail  string
	// Command is the exact host command; empty means there is no single command.
	Command string
	// Reason is prose guidance shown when there is no command.
	Reason string
}

Finding is a check result plus what the operator must do elsewhere.

type Fix

type Fix struct {
	ID         string
	CheckID    string
	Subject    string
	Kind       Kind
	Title      string
	Why        string
	Risk       Risk
	Reversible bool
	// Needs is the API ability the caller must hold to apply.
	Needs string
	// Detect re-runs the originating check and plans the fix.
	Detect func(ctx context.Context) (Applicability, error)
	// Run performs the change; nil for guided and manual fixes.
	Run func(ctx context.Context, in Input) error
}

Fix is one registered remedy for one check.

func ControlPlaneBackupFix

func ControlPlaneBackupFix(d BackupDeps) Fix

ControlPlaneBackupFix takes a fresh control plane snapshot when the newest one is stale.

func DiskFix

func DiskFix(d DiskDeps) Fix

DiskFix routes the "Clean up now" action through the engine.

func GuidedCheckFix

func GuidedCheckFix(d GuidedDeps) Fix

GuidedCheckFix offers Re-check as the action and the host command as the secondary option.

func LegacyTokensFix

func LegacyTokensFix(d LegacyTokensDeps) Fix

LegacyTokensFix migrates pending pre-upgrade API tokens now instead of on first use.

func NetworkPoolFix

func NetworkPoolFix(d NetworkPoolDeps) Fix

NetworkPoolFix prunes orphaned app networks when the subnet pool runs high.

func OrphansFix

func OrphansFix(d OrphansDeps) Fix

OrphansFix previews and prunes unreferenced Docker data for the docker_orphans check.

func PublicAddressFix

func PublicAddressFix(d PublicAddressDeps) Fix

PublicAddressFix persists the address agents dial, overriding the env var.

func UDPPortFix

func UDPPortFix(d UDPPortDeps) Fix

UDPPortFix names the holder of the mesh UDP port and how to free it. The port is a compiled default today, so there is no "pick another port" tier.

func WireGuardPrivilegeFix

func WireGuardPrivilegeFix(d WireGuardDeps) Fix

WireGuardPrivilegeFix returns the guided fix for a mesh blocked by privileges.

type GuidedDeps

type GuidedDeps struct {
	ID      string
	CheckID string
	Subject string
	Title   string
	Why     string
	Risk    Risk
	Check   func(ctx context.Context) (Finding, error)
}

GuidedDeps describes a fix for a host-level step the control plane cannot do.

type HostEnv

type HostEnv struct {
	Mode        string
	Unit        string
	Root        bool
	TunPresent  bool
	CapNetAdmin bool
	Executable  string
}

HostEnv is how this process is running, read from /proc and the filesystem.

func DetectHostEnv

func DetectHostEnv(r HostReader) HostEnv

DetectHostEnv classifies the run mode and the privileges the process has.

type HostReader

type HostReader struct {
	ReadFile   func(path string) ([]byte, error)
	Exists     func(path string) bool
	Getenv     func(key string) string
	Geteuid    func() int
	Executable func() string
}

HostReader is the injectable view of the host DetectHostEnv reads.

func SystemHostReader

func SystemHostReader() HostReader

SystemHostReader reads the real host.

type Input

type Input struct {
	Actor  string
	Params map[string]string
}

Input is what Run receives.

type Kind

type Kind string

Kind is how much of a fix the control plane can do itself.

const (
	KindAuto   Kind = "auto"
	KindGuided Kind = "guided"
	KindManual Kind = "manual"
)

Kind values: the control plane applies it, shows an exact command, or only explains.

type LegacyTokensDeps

type LegacyTokensDeps struct {
	// Pending counts pre-upgrade tokens not yet migrated.
	Pending func(ctx context.Context) (int, error)
	// Migrate imports every pending token; nil means the auth library is not configured.
	Migrate func(ctx context.Context) error
}

LegacyTokensDeps are the facts and the importer the legacy-token fix uses.

type NetworkPoolDeps

type NetworkPoolDeps struct {
	Usage func(ctx context.Context) (enabled bool, inUse, capacity int, err error)
	// Orphans lists networks a prune would remove.
	Orphans func(ctx context.Context) ([]string, error)
	Prune   func(ctx context.Context) (removed []string, err error)
	// WarnPercent is the usage above which the check fails.
	WarnPercent int
	// PoolEnv names the env var that widens the pool.
	PoolEnv string
}

NetworkPoolDeps are the facts and the pruner the pool fix uses.

type Option

type Option struct {
	Value string `json:"value"`
	Label string `json:"label"`
}

Option is a candidate value for a fix parameter.

type OrphansDeps

type OrphansDeps struct {
	Check       func(ctx context.Context) (CheckState, error)
	Reclaimable func(ctx context.Context) (DiskReclaim, error)
	Prune       func(ctx context.Context) (freed int64, err error)
}

OrphansDeps are the facts and the pruner the orphaned-Docker-data fix uses.

type OutcomeStatus

type OutcomeStatus string

OutcomeStatus is the result of one apply or re-check.

const (
	OutcomeFixed         OutcomeStatus = "fixed"
	OutcomeStillFailing  OutcomeStatus = "still_failing"
	OutcomeCannotFixHere OutcomeStatus = "cannot_fix_here"
	OutcomeSkipped       OutcomeStatus = "skipped"
)

Outcome values for an apply or re-check.

type Param

type Param struct {
	Name    string   `json:"name"`
	Options []Option `json:"options"`
	Default string   `json:"default,omitempty"`
	Free    bool     `json:"free"`
}

Param is the one input a fix may ask for.

type PortHolder

type PortHolder struct {
	Process   string
	PID       int
	Container string
}

PortHolder names what is bound to a port.

type PublicAddressDeps

type PublicAddressDeps struct {
	Check      func(ctx context.Context) (CheckState, error)
	Candidates func(ctx context.Context) []Option
	Save       func(ctx context.Context, host, actor string) error
}

PublicAddressDeps are the facts and the setter the address fix uses.

type Result

type Result struct {
	FixID   string        `json:"fix_id"`
	Outcome OutcomeStatus `json:"outcome"`
	Detail  string        `json:"detail"`
	View    View          `json:"view"`
}

Result is the outcome of Apply.

type Risk

type Risk string

Risk is the worst thing applying a fix can do.

const (
	RiskSafe     Risk = "safe"
	RiskRestarts Risk = "restarts"
	RiskExposes  Risk = "exposes"
)

Risk values, from harmless to externally visible.

type State

type State string

State is where a fix stands for its subject right now.

const (
	StateHealthy     State = "healthy"
	StateOffer       State = "offer"
	StateDemoted     State = "demoted"
	StateRateLimited State = "rate_limited"
)

State values for a fix against its subject.

type Store

type Store interface {
	RecentAttempts(ctx context.Context, fixID, subject string, limit int) ([]Attempt, error)
	CountAttemptsSince(ctx context.Context, fixID string, since time.Time) (int, error)
	RecordAttempt(ctx context.Context, a Attempt) error
}

Store persists attempt memory.

type UDPPortDeps

type UDPPortDeps struct {
	Check  func(ctx context.Context) (CheckState, error)
	Port   int
	Holder func(ctx context.Context, port int) (PortHolder, bool)
}

UDPPortDeps are the facts the busy-port fix needs.

type View

type View struct {
	ID         string        `json:"id"`
	CheckID    string        `json:"check_id"`
	Subject    string        `json:"subject"`
	Title      string        `json:"title"`
	Why        string        `json:"why"`
	Risk       Risk          `json:"risk"`
	Reversible bool          `json:"reversible"`
	Needs      string        `json:"needs"`
	State      State         `json:"state"`
	BaseKind   Kind          `json:"base_kind"`
	Kind       Kind          `json:"kind"`
	Failing    bool          `json:"failing"`
	Detail     string        `json:"detail"`
	Reason     string        `json:"reason,omitempty"`
	Changes    []Change      `json:"changes"`
	Command    string        `json:"command,omitempty"`
	Param      *Param        `json:"param,omitempty"`
	LastTried  *Attempt      `json:"last_attempt,omitempty"`
	Attempts   []Attempt     `json:"attempts"`
	Blocked    string        `json:"blocked,omitempty"`
	RetryAfter time.Duration `json:"-"`
}

View is a fix as the API and UI show it.

type WireGuardDeps

type WireGuardDeps struct {
	Check func(ctx context.Context) (CheckState, error)
	Host  func() HostEnv
	// FallbackUnit names the systemd unit when the cgroup does not.
	FallbackUnit string
}

WireGuardDeps are the host facts the privilege fix reasons over.

Jump to

Keyboard shortcuts

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