Documentation
¶
Overview ¶
Package orphans is the single definition of a leftover container or volume that desired state no longer accounts for. The reaper, the API and the CLI all classify through it so they cannot disagree.
Index ¶
- Constants
- func DesiredServiceContainerNames(svc store.DesiredService) []string
- func IsManaged(c docker.ContainerState, d Desired, instanceID string) bool
- func ServedSet(hosts []string) map[string]bool
- type CertBackend
- type Config
- type Controller
- type Deps
- type Desired
- type Failure
- type Finding
- type Kind
- type Mode
- type Orphan
- type Reaper
- type Reason
- type Report
- type Source
- type Store
- type VolumeBackend
Constants ¶
const ( SkipTeardownPending = "app teardown is still pending" SkipSupersededBuild = "an older generation of a live app, owned by its reconciler" SkipNotOurs = "not created by this control plane" SkipNoRunningCopy = "the node it is placed on has no running copy yet" SkipUnrecognized = "name does not match a managed container shape" SkipDatabaseVolume = "database data volumes are never removed automatically" SkipMounted = "volume is mounted by a container" SkipVolumesOff = "automatic volume removal is disabled" )
Skip reasons explain why an orphan is listed but not auto-removable.
const ( EnvMode = "APP_ORPHAN_REAPER" EnvGrace = "APP_ORPHAN_GRACE" EnvReapVolumes = "APP_ORPHAN_REAP_VOLUMES" EnvVolumeGrace = "APP_ORPHAN_VOLUME_GRACE" EnvCertGrace = "APP_ORPHAN_CERT_GRACE" EnvMaxRemovals = "APP_ORPHAN_MAX_REMOVALS" EnvInterval = "APP_ORPHAN_INTERVAL" )
Environment variables that tune the reaper.
Variables ¶
This section is empty.
Functions ¶
func DesiredServiceContainerNames ¶
func DesiredServiceContainerNames(svc store.DesiredService) []string
DesiredServiceContainerNames is every replica container name svc's desired state can produce.
Types ¶
type CertBackend ¶
type CertBackend interface {
ListCertStorageKeys(ctx context.Context, prefix string, recursive bool) ([]string, error)
DeleteCertStorageValue(ctx context.Context, key string) error
}
CertBackend lists and deletes stored certificate files. *store.DB satisfies it.
type Config ¶
type Config struct {
Mode Mode
Grace time.Duration
VolumeGrace time.Duration
CertGrace time.Duration
ReapVolumes bool
MaxPerPass int
// Interval is the minimum time between scheduled passes.
Interval time.Duration
}
Config tunes the reaper.
func ConfigFromEnv ¶
ConfigFromEnv reads the reaper settings, falling back to DefaultConfig for anything unset or malformed.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig is the safe default: containers reaped after 15 minutes, volumes only listed.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller adapts a Reaper to the reconcile loop.
type Deps ¶
type Deps struct {
Store Store
NodeIDs func(ctx context.Context) ([]string, error)
NormNode func(nodeID string) string
Resolve func(nodeID string) (docker.Runtime, error)
Volumes VolumeBackend
Certs CertBackend
// ServedHosts reports the hostnames ingress serves; known is false until it has applied a config.
ServedHosts func(ctx context.Context) (hosts []string, known bool, err error)
InstanceID string
Config Config
Logger *slog.Logger
Now func() time.Time
}
Deps are the Reaper's collaborators.
type Desired ¶
type Desired struct {
Services map[string]bool
ContainerNames map[string]bool
// ContainerNode maps each desired container name to the node it belongs on.
ContainerNode map[string]string
Databases map[string]bool
VolumeNames map[string]bool
PendingTeardown map[string]bool
}
Desired is the slice of desired state classification needs.
func LoadDesired ¶
LoadDesired snapshots desired state from src. normNode maps a stored node ID to the ID the scanner uses for it ("" for the control plane's own node).
type Finding ¶
type Finding struct {
Orphan
FirstSeenAt *time.Time `json:"first_seen_at,omitempty"`
ReapAfter *time.Time `json:"reap_after,omitempty"`
Due bool `json:"due"`
}
Finding is an Orphan plus where it stands against the grace period.
type Orphan ¶
type Orphan struct {
Kind Kind `json:"kind"`
Name string `json:"name"`
ID string `json:"id,omitempty"`
NodeID string `json:"node_id"`
Reason Reason `json:"reason"`
Image string `json:"image,omitempty"`
SizeBytes int64 `json:"size_bytes,omitempty"`
// PlacedOn is the node desired state now places a misplaced container on.
PlacedOn string `json:"placed_on,omitempty"`
// Skip is non-empty when the reaper must leave this resource alone.
Skip string `json:"skip,omitempty"`
}
Orphan is one leftover resource on one node.
func ClassifyCertificate ¶
ClassifyCertificate reports whether the certificate filed under domain (a Caddy storage directory name) is for a hostname nothing serves.
func ClassifyContainer ¶
func ClassifyContainer(c docker.ContainerState, d Desired, instanceID, nodeID string) (Orphan, bool)
ClassifyContainer reports whether c is an orphan. instanceID is this control plane's own instance label, empty when instances are not scoped.
func ClassifyVolume ¶
func ClassifyVolume(v docker.NamedVolume, d Desired, nodeID string, reapVolumes bool) (Orphan, bool)
ClassifyVolume reports whether v is an orphan. reapVolumes is the operator's opt-in for automatic volume removal.
type Reaper ¶
type Reaper struct {
Deps
// contains filtered or unexported fields
}
Reaper removes orphans once they have stayed orphaned past the grace period.
type Reason ¶
type Reason string
Reason says why a resource is considered an orphan.
const ( ReasonServiceDeleted Reason = "service_deleted" ReasonDatabaseDeleted Reason = "database_deleted" ReasonMisplaced Reason = "misplaced" ReasonStaleGeneration Reason = "stale_generation" ReasonUnmanaged Reason = "unmanaged" ReasonForeignInstance Reason = "foreign_instance" ReasonUnrecognized Reason = "unrecognized_name" ReasonUnreferenced Reason = "unreferenced_volume" ReasonUnserved Reason = "unserved_certificate" )
Orphan reasons.
type Report ¶
type Report struct {
DryRun bool `json:"dry_run"`
Findings []Finding `json:"findings"`
Removed []Orphan `json:"removed"`
Failed []Failure `json:"failed,omitempty"`
// Unreachable lists nodes that could not be scanned this pass.
Unreachable []string `json:"unreachable,omitempty"`
// Halted explains why removal was withheld, empty when it was not.
Halted string `json:"halted,omitempty"`
}
Report is what one pass saw and did.
type Source ¶
type Source interface {
ListDesiredServices(ctx context.Context) ([]store.DesiredService, error)
ListDesiredDatabases(ctx context.Context) ([]store.DesiredDatabase, error)
ListPendingTeardowns(ctx context.Context) ([]store.PendingTeardown, error)
}
Source is the persistence LoadDesired reads. *store.DB satisfies it.
type Store ¶
type Store interface {
Source
RecordOrphanSighting(ctx context.Context, kind, nodeID, name string, at time.Time) error
ClearOrphanSighting(ctx context.Context, kind, nodeID, name string) error
ListOrphanSightings(ctx context.Context) ([]store.OrphanSighting, error)
SaveAuditEntry(ctx context.Context, e store.AuditEntry) error
}
Store is the persistence the Reaper needs. *store.DB satisfies it.
type VolumeBackend ¶
type VolumeBackend interface {
ListNamedVolumes(ctx context.Context) ([]docker.NamedVolume, error)
RemoveVolume(ctx context.Context, name string) error
}
VolumeBackend lists and removes named volumes on the control plane's own node. *docker.Client satisfies it. Remote nodes are containers-only.