kustomize

package
v0.4.6 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: AGPL-3.0 Imports: 43 Imported by: 0

Documentation

Overview

Package kustomize wraps sigs.k8s.io/kustomize/api so the rest of flate never invokes the `kustomize` CLI. It provides:

  • RenderFlux: render a Flux Kustomization to YAML documents entirely in memory. It reproduces the kustomize-controller's spec merge (generate.go) and builds against a memory-over-disk overlay (overlayfs.go) rooted at the source — source files are read from a secure on-disk FS, the merged kustomization.yaml + any pre-fetched remote resources are written to an in-memory layer, and the source tree is never copied or mutated.
  • Prepare: the standard pre-render dance (Clone + expand postBuild.substituteFrom) for embedders rendering a single Kustomization. Symmetric to helm.Prepare for HelmReleases, minus a values cache — the substituteFrom path has no YAML parse to memoize; see Prepare's docstring.
  • Substitute: envsubst-style "${VAR}" / "${VAR:=default}" used for Flux post-build substitutions.

Concurrency. Each RenderFlux call builds against its own private overlay, so no two renders share mutable state and there is no per-tree build lock. krusty's package-global state (the openapi schema registry, builtin plugin/transformer factories) is still not goroutine-safe, so the process-wide BuildMutex (flux.go) serializes EVERY krusty invocation flate runs — including the helm post-renderer's krusty.Run in pkg/helm. fluxcd/pkg/kustomize guards its own Build for the same reason; every flate-owned krusty entrypoint MUST hold BuildMutex.

Caching boundary. kustomize output caching is deferred to the controller layer (the Kustomization controller's spec+source fingerprint dedup), NOT memoized inside this package the way helm.Client caches template output. krusty plugins/generators are not guaranteed deterministic, so the stable point to memoize is the coarse spec+source hash the controller already computes — not the render engine's fluid internals.

Index

Constants

This section is empty.

Variables

View Source
var BuildMutex sync.Mutex

BuildMutex serializes every krusty/kustomize build flate runs in a process. kustomize's krusty pipeline mutates package-global state (the openapi schema registry + builtin-plugin/transformer factories) that is NOT goroutine-safe — fluxcd/pkg/kustomize guards its own Build with an internal mutex for exactly this reason, but that mutex does not extend to OTHER krusty entrypoints in the same process (flate's helm postRenderer runs krusty.Run directly). Two concurrent builds — one KS Build, one HR postRender — race on the shared globals and produce nondeterministic corruption: empty / torn rendered output surfacing as "missing metadata.name" decode errors, dropped resources, or cascade failures that flip run-to-run. Every flate-owned krusty invocation MUST hold this lock.

Functions

func Prepare

Prepare runs the standard pre-render dance for a Kustomization so it is ready to feed into RenderFlux:

  1. Clone ks so subsequent mutations don't touch the store-canonical copy (the immutability contract every flate controller honors — see pkg/manifest/doc.go).
  2. Expand spec.postBuild.substituteFrom references against the supplied values provider so ks.PostBuildSubstitute reflects the merged result a render would consume.

Embedders rendering a single Kustomization without standing up the orchestrator's KS controller call Prepare then RenderFlux.

Unlike helm.Prepare, Prepare takes no *values.Cache — and that asymmetry is intentional, not an oversight. The helm valuesFrom path yaml.Unmarshals each ref into a nested map[string]any, so a platform-wide values CM referenced by N HRs is worth parsing once and memoizing. The substituteFrom path resolves only FLAT string vars (CM/Secret data -> map[string]string via decodeBag), does no yaml.Unmarshal, and the per-KS work that dominates its cost (the newline strip + varname-regex validation + UpdatePostBuildSubstitutions) runs regardless of any lookup cache. There is no parsed tree to memoize. BenchmarkExpandPostBuildSubstituteReference_SharedCM (pkg/values) measures the whole path at single-digit microseconds per KS even for a large shared CM — sub-millisecond aggregate across a big repo — so threading a cache here would add wiring for no measurable gain.

func RenderFlux

func RenderFlux(ctx context.Context, cache *TreeCache, sourceRoot string, applyIgnore bool, subPath string, rawSpec map[string]any) ([]byte, error)

RenderFlux renders a Flux kustomize.toolkit.fluxcd.io Kustomization entirely in memory, using the same merge + build the kustomize-controller performs.

sourceRoot is resolved and wrapped in a secure on-disk FS once per root (memoized in cache.diskRootFor); each render derives its own private memory-over-disk overlay from that shared disk FS, writes the merged kustomization.yaml + any pre-fetched remote resources into the overlay's in-memory layer, and builds with fluxkustomize.Build. The source tree is never copied or mutated and no two renders share mutable state, so renders run fully parallel with no staging lock. The secure disk layer confines reads to the root (a path escaping it simply does not resolve), giving SecureBuild's security posture for free.

applyIgnore selects whether source-controller's default file exclusions (.sops.yaml, binaries, CI dirs, in-tree .sourceignore) are applied while auto-generating a kustomization — true for working-tree / self-referential sources that never passed through a fetcher's artifact filtering, false for already-filtered fetched artifacts. spec.commonMetadata is applied post-build (the Generator does not handle it, mirroring kustomize-controller's apply-time pass).

ctx is honored at coarse boundaries (entry, before build) because fluxkustomize.Build does not itself accept a ctx.

func Substitute

func Substitute(data []byte, vars map[string]string) ([]byte, error)

Substitute replaces ${var} placeholders in data using the supplied vars map. Delegates to fluxcd/pkg/envsubst — the exact engine Flux source-controller uses — so behavior matches Flux bit-for-bit:

  • $${VAR} passes through as literal ${VAR} (escape).
  • ${VAR:-default}, ${VAR:=default}, ${VAR:+alt}, ${VAR:?msg} handle the unset case per POSIX parameter expansion.
  • Bash-only constructs like ${VAR[@]} or ${VAR%%:*} that aren't recognized by envsubst are emitted literally, not erroneously matched as bare variable references (a divergence the previous regex-based implementation had).
  • Undefined ${VAR} without a default expands to the empty string, matching kustomize-controller's default (strict mode is the opt-in `StrictPostBuildSubstitutions` feature gate, off by default). Returning the empty string with exists=true keeps envsubst out of its strict-mode error path and lines flate up with what real Flux renders against an incomplete substitute map.

Types

type GitBaseFetcher added in v0.3.4

type GitBaseFetcher func(ctx context.Context, repoURL, ref string) (localPath, revision string, err error)

GitBaseFetcher materializes a remote kustomize git base — a repo URL at a bare, undifferentiated ref (tag, branch, commit, or "" for the default branch) — into an on-disk worktree, returning its absolute path and the resolved revision. The orchestrator supplies a closure over its *git.Fetcher; this package only ever sees the function value, keeping it free of the pkg/source → pkg/kustomize import cycle.

type TreeCache added in v0.3.4

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

TreeCache carries the state shared across one run's renders.

func NewTreeCache added in v0.3.4

func NewTreeCache() *TreeCache

NewTreeCache constructs an empty render cache.

func (*TreeCache) FetchRemote added in v0.3.4

func (c *TreeCache) FetchRemote(ctx context.Context, urlStr string) ([]byte, error)

FetchRemote returns the body of urlStr, fetched at most once per (url, success) cache entry. Successful bodies are cached for the TreeCache lifetime; transient errors (DNS, connection reset, timeout, 5xx) are NOT cached — the next caller retries. Only definitive HTTP 4xx responses are cached as negative entries (they won't change between retries within a run).

Without the success-only cache, a single transient hiccup at orchestrator startup poisoned every subsequent reconcile of every KS referencing that URL for the rest of the run.

The fetch runs in a background goroutine seeded with a detached context (httpGetURL applies remoteFetchTimeout internally) so a cancellation on the first caller doesn't propagate into the cached error. Each caller still honors its own ctx via the select below.

func (*TreeCache) SetGitBaseFetcher added in v0.3.4

func (c *TreeCache) SetGitBaseFetcher(fn GitBaseFetcher)

SetGitBaseFetcher wires the git-clone capability used to resolve remote git bases referenced from a kustomization's resources:. The orchestrator calls this once at construction; library/test embedders may leave it unset.

func (*TreeCache) SetRenderCache added in v0.4.4

func (c *TreeCache) SetRenderCache(dir string, capBytes int64)

SetRenderCache enables the cross-run render cache, persisting under dir with a capBytes disk cap (<=0 or empty dir disables it). The orchestrator calls this once at construction; embedders/tests may leave it unset for an always-render TreeCache.

Jump to

Keyboard shortcuts

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