apply

package
v0.7.5 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package apply contains server-side apply and prune integration points.

Index

Constants

View Source
const (
	// FieldManager is the SSA field manager name used by the controller.
	// Distinguishes from "opm-cli", "kubectl", "helm", etc.
	// From docs/design/ssa-ownership-and-drift-policy.md.
	FieldManager = "opm-controller"
)

Variables

This section is empty.

Functions

func IsServiceAccountNotFound added in v0.6.0

func IsServiceAccountNotFound(err error) bool

IsServiceAccountNotFound reports whether err was produced by NewImpersonatedClient because the target ServiceAccount did not exist. The wrapping chain preserves the apiserver's NotFound status so callers can branch deletion-cleanup behavior without introducing a sentinel type.

func NewImpersonatedClient

func NewImpersonatedClient(
	ctx context.Context,
	cfg *rest.Config,
	reader client.Reader,
	scheme *runtime.Scheme,
	namespace, saName string,
) (client.Client, error)

NewImpersonatedClient builds a controller-runtime client that impersonates the given ServiceAccount for all API calls. The SA must exist in the specified namespace; if it does not, an error is returned so the caller can stall the reconcile.

reader is used only for the SA existence check. Pass an uncached reader (e.g. manager.GetAPIReader()) so that a single Get does not provision a cluster-wide ServiceAccount informer and thereby require list/watch RBAC. scheme is used to build the impersonated client.

The returned client is suitable for Apply and Prune operations scoped to the SA's RBAC bindings.

func NewResourceManager

func NewResourceManager(c client.Client, owner string) *fluxssa.ResourceManager

NewResourceManager constructs a Flux SSA ResourceManager with the opm-controller field manager. The owner string is used for SSA ownership labels.

A StatusPoller is wired in because fluxssa.ApplyAllStaged internally calls WaitForSet after applying cluster-scoped resources (CRDs, ClusterRoles, Namespaces); a nil poller there nil-derefs on the first module whose render contains any such resource.

Types

type ApplyResult

type ApplyResult struct {
	// Created is the number of resources created (did not exist before).
	Created int

	// Updated is the number of resources updated (existed, fields changed).
	Updated int

	// Unchanged is the number of resources unchanged (existed, no field diff).
	Unchanged int
}

ApplyResult carries counts of apply outcomes.

func Apply

func Apply(
	ctx context.Context,
	rm *fluxssa.ResourceManager,
	resources []*unstructured.Unstructured,
	force bool,
) (*ApplyResult, error)

Apply applies the given resources to the cluster using Server-Side Apply. Staging is handled by Flux's ApplyAllStaged, which applies cluster definitions (CRDs, Namespaces, ClusterRoles) first with readiness waits, then class definitions, then everything else. See docs/design/flux-ssa-staging.md.

When force is true, immutable field conflicts are resolved by recreating the object (maps to ApplyOptions.Force, not SSA field-ownership conflicts — Flux always applies with ForceOwnership).

Returns an ApplyResult with counts, or an error on any apply failure.

type DriftResult

type DriftResult struct {
	// Drifted is true if any resource has drifted from desired state.
	Drifted bool

	// Resources lists the resources that have drifted.
	Resources []DriftedResource
}

DriftResult holds the outcome of drift detection across a resource set.

func DetectDrift

func DetectDrift(
	ctx context.Context,
	rm *fluxssa.ResourceManager,
	resources []*unstructured.Unstructured,
) (*DriftResult, error)

DetectDrift performs SSA dry-run diffs for each resource and returns which resources have drifted from desired state. Uses Flux's ResourceManager.Diff which performs a server-side apply dry-run and compares the result.

A resource is considered drifted when the dry-run result differs from the desired state (Flux returns ConfiguredAction). Resources that don't exist yet (CreatedAction) or are unchanged are not considered drifted.

Returns an error only when the dry-run API call itself fails (transient). Drift detection results are not errors — drift is an expected operational signal.

type DriftedResource

type DriftedResource struct {
	Group     string
	Kind      string
	Namespace string
	Name      string
}

DriftedResource identifies a single resource that has drifted from desired state.

type PruneResult

type PruneResult struct {
	// Deleted is the number of stale resources successfully deleted.
	Deleted int

	// Skipped is the number of stale resources skipped due to safety exclusions.
	Skipped int
}

PruneResult carries counts of prune outcomes.

func Prune

func Prune(
	ctx context.Context,
	c client.Client,
	ownerUUID string,
	stale []releasesv1alpha1.InventoryEntry,
) (*PruneResult, error)

Prune deletes stale resources from the cluster. Uses direct client.Delete per resource rather than Flux's DeleteAll to allow per-resource error control and safety exclusion logic (design decision 1).

Safety exclusions (design decision 3: hard-coded, not configurable):

  • Namespace: never auto-deleted (cascades to all resources inside)
  • CustomResourceDefinition: never auto-deleted (deletes all instances globally)

Live-state ownership guard (defense-in-depth): before each delete, Prune GETs the live object and skips the delete if the live object is not OPM-managed (missing/unrecognized app.kubernetes.io/managed-by label) or carries a module-release.opmodel.dev/uuid label that disagrees with ownerUUID. An empty live UUID label is tolerated (legacy resources predate UUID stamping). An empty ownerUUID disables the UUID comparison — callers that cannot supply a UUID (e.g. the Release reconciler, or a freshly-created ModuleRelease whose Status.ReleaseUUID is not yet persisted) fall back to the managed-by check alone.

Skipped resources are logged as warnings and counted in PruneResult.Skipped.

If a stale resource is already gone (NotFound), it is treated as success. Individual failures (Get or Delete) are collected and returned as a joined error; remaining entries continue (design decision 2: continue-on-error / fail-slow).

The caller is responsible for:

  • Computing the stale set via internal/inventory.ComputeStaleSet
  • Checking spec.prune before calling this function
  • Ensuring apply succeeded before calling prune
  • Supplying ownerUUID from the freshly-rendered resources or ModuleReleaseStatus.ReleaseUUID

Jump to

Keyboard shortcuts

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