Documentation
¶
Overview ¶
Package prune deletes the resources of an application that has left the app set.
App-of-apps (#47, decision D-e) is deliberately report-only: an application dropped from the git app set stops being reconciled and its stack is left running and surfaced as orphaned. This package is the acting half (#54), behind its own opt-in, because reporting an orphan is safe and deleting one is not.
Two senses of "prune" ¶
The chart engine already has Engine.Prune, and it means something else: trimming an individual release's revision history to the last N, which this repository exposes as SyncPolicy.HistoryMax. Nothing here touches revision history. "Prune" in this package always means deleting a release's deployed resources.
Why the swarm is the source of truth ¶
The obvious signal — the list of applications the running loop watched leave — does not survive a restart, and a controller that forgot its orphans on every restart would leave exactly the stacks nobody is looking at. So the departure is not remembered; it is rediscovered. Every release this controller installs carries the owner stamp application.OwnerID writes, and that stamp is stored on the swarm. Any release stamped for an application the app set no longer declares has, by definition, been left behind.
The stamp is also what makes deletion safe. A release without one, or with one another tool wrote, is unmanaged here and is never a candidate — the same distinction charts.Plan draws between Orphaned and Unmanaged, for the same reason.
The stamp is not enough on its own ¶
A stamp records who installed a release, and it is only rewritten when something deploys that release again. Rename an application without changing anything else and the plan comes out identical, so nothing is deployed and nothing is re-stamped: the release keeps the departed name's stamp indefinitely, and reading the stamp alone would delete a stack that a current application is reconciling (#62). So the sweep is given the releases the current applications declare as well, and spares anything in that list. The stamp says who installed it; that list says whether anybody is still responsible for it.
Two controllers on one swarm ¶
The stamp names a controller as well as an application, and the sweep only considers its own. Without that, a second swarmcli-cd sharing the swarm would answer "which releases belong to an application my app set no longer declares" about the *first* controller's applications, and delete them — a silent, swarm-wide deletion of somebody else's work, triggered by nothing more than starting a second controller.
Two controllers on one swarm must therefore be given distinct ids. The default is shared, so two controllers that both take it will still collide; that is a deployment mistake this package cannot detect from the inside, because a controller cannot tell "my own releases from before a restart" from "another controller using my id".
One swarm ¶
The sweep covers the swarm this controller runs in, because swarms.Registry resolves exactly that one and cannot enumerate others (D2). That is complete for the OSS build. A multi-swarm companion replacing the seam would have to extend it with a lister before this could find a departed application's releases on a swarm it no longer names.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Release ¶
func Release(ctx context.Context, backend charts.Backend, engine Uninstaller, release string, volumes bool) (*charts.UninstallResult, error)
Release deletes one release's deployed resources and then its records, in that order, and reports the networks the engine left behind.
The order is the whole point. charts.Engine.Uninstall aggregates its errors and deletes the release-history configs regardless of whether its own stack removal worked — and those configs carry the owner stamp, which is the only thing that lets a later sweep find this release again. Calling it directly on a stack that will not come down would delete the evidence and strand the resources permanently, invisible to every future prune. So the resources come down first, through the backend, and the records are only deleted once there is nothing left for them to point at.
This is shared with the per-application prune in reconcile, which faces the same hazard for the same reason.
Types ¶
type Engine ¶
Engine is the part of the chart engine a sweep uses. *charts.Engine implements it.
Declared here rather than reused from reconcile so that prune does not import the reconciler for an interface it can state itself.
type Options ¶
type Options struct {
Swarms swarms.Registry
Engine func(charts.Backend) Engine
// Volumes extends the deletion to the named volumes of what it removes.
// Off by default, and the only irreversible part: everything else prune
// deletes is recreated from git the moment the application comes back.
Volumes bool
// ControllerID is this controller's half of the owner stamp, and bounds
// what the sweep will consider at all. Empty is
// application.DefaultControllerID — which is correct for the single
// controller case and wrong the moment there are two, so a second
// controller on the swarm must be given its own.
ControllerID string
Log *slog.Logger
}
Options configures a Pruner. Everything has a working default.
type Pruner ¶
type Pruner struct {
// contains filtered or unexported fields
}
Pruner deletes the releases of applications that have left the app set.
func New ¶
New returns a Pruner. A nil Pruner is the report-only default, so callers construct one only when prune is enabled.
func (*Pruner) Departed ¶
Departed deletes the releases of every application this controller owns that is absent from desired, and returns the applications it emptied.
desired must be an app set that has actually loaded. The caller vouches for that: this cannot tell "the set declares nothing" apart from "the set could not be read", and the two want opposite things done. See appset.Loop, which only calls this after a load and an apply have both succeeded.
declared names the releases the applications still in the set hold, and no release named in it is ever deleted whatever its stamp says. That is what makes renaming an application a handover rather than a teardown (#62): the release keeps the departed application's stamp until something re-stamps it, and under the default sync policy nothing does, because re-stamping means deploying and a manual-policy application is not deployed without being asked. The stamp answers "who installed this"; declared answers "is anybody still responsible for it", and only the second is a safe basis for deleting.
Every application is attempted and the failures are collected rather than returned at the first. They are independent, and because the next sweep rediscovers whatever is still stamped on the swarm, a failure costs a reconcile interval rather than an orphan nobody looks at again.
type Uninstaller ¶
type Uninstaller interface {
Uninstall(ctx context.Context, release string, purgeVolumes bool) (*charts.UninstallResult, error)
}
Uninstaller deletes a release's recorded revisions once its resources are gone. *charts.Engine implements it.